Loading...

Manual de Usuario — GoScript IDE

Proyecto 2 · Organización de Lenguajes y Compiladores 1
Universidad de San Carlos de Guatemala — Facultad de Ingeniería
Escuela de Ingeniería en Ciencias y Sistemas
Primer Semestre 2026

Autor: Mynor Cifuentes · Carné 201318644


Índice

  1. ¿Qué es GoScript?
  2. Instalación y primer uso
  3. Recorrido por el IDE
  4. Tu primer programa
  5. Variables y tipos
  6. Operadores
  7. Control de flujo
  8. Funciones
  9. Slices
  10. Structs
  11. Funciones embebidas
  12. Reportes
  13. Atajos de teclado
  14. Solución de problemas
  15. Limitaciones

1. ¿Qué es GoScript?

GoScript es un lenguaje de programación interpretado, fuertemente tipado e
inspirado en Go, creado para el segundo proyecto del curso. El IDE web te
permite:

  • Escribir, editar y guardar archivos .gst.
  • Ejecutar tu programa y ver la salida en una consola integrada.
  • Inspeccionar errores léxicos, sintácticos y semánticos en una tabla.
  • Revisar la tabla de símbolos generada durante la ejecución.
  • Visualizar el árbol de sintaxis abstracta (AST) como un diagrama.
  • Trabajar con varios archivos a la vez gracias al sistema de pestañas.

2. Instalación y primer uso

Requisitos

  • Node.js 18 o superior (recomendado 20+).
  • npm (viene con Node).
  • Un navegador moderno (Chrome, Firefox, Edge, Safari).

Pasos

Abre dos terminales en la raíz del proyecto.

Terminal 1 — Backend:

1
2
3
cd backend
npm install
npm run dev

Verás el mensaje [GoScript] API escuchando en http://localhost:3001.

Terminal 2 — Frontend:

1
2
3
cd frontend
npm install
npm run dev

Vite te dará una URL, normalmente http://localhost:5173/. Ábrela en tu
navegador y deberías ver el IDE listo para usar.

Nota: la primera vez tarda un poco más porque npm install descarga
dependencias y npm run dev del backend genera el parser con Jison.


3. Recorrido por el IDE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──────────────────────────────────────────────────────────────────┐
│ GoScript IDE [Nuevo][Abrir][Guardar] ▶ Ejecutar
├──────────────────────────────────────────────────────────────────┤
│ ┌─ programa.gst × ─┐ ┌─ otro.gst × ─┐ + │
│ │ │
│ │ func main() { ┌────────────────────────────────┐ │
│ │ fmt.Println("Hola") │ Consola | Errores | Símbolos | │ │
│ │ } │ | | | │ │
│ │ │ | | AST | │ │
│ │ (Editor Monaco) │ Hola, GoScript! │ │
│ │ │ │ │
│ │ │ │ │
│ └──────────────────────────────┴────────────────────────────────┘ │
│ GoScript IDE · v0.9 2 pestañas · API: http://localhost:3001 │
└──────────────────────────────────────────────────────────────────┘

Zonas principales

  • Barra superior: nombre del archivo activo (editable in-place) y los
    botones Nuevo, Abrir, Guardar y Ejecutar.
  • Barra de pestañas: una por archivo abierto. Click izquierdo para
    cambiar, click central o × para cerrar. El botón + agrega una nueva.
  • Editor: Monaco con resaltado de sintaxis Go, minimapa, números de
    línea y autoindentación.
  • Panel lateral: cuatro vistas para inspeccionar el resultado de la
    ejecución más reciente (Consola, Errores, Tabla de Símbolos, AST).
  • Pie: indicador de cantidad de pestañas, marca de “sin guardar” y URL
    del API que está usando el frontend.

Pestaña sucia

Cuando una pestaña tiene cambios sin guardar, aparece un punto al lado del
nombre. Si intentas cerrarla o cerrar el navegador, el IDE pedirá
confirmación para evitar perder trabajo.


4. Tu primer programa

El IDE arranca con un archivo programa.gst que contiene:

1
2
3
4
5
6
// Bienvenido a GoScript
// Escribe tu código aquí y presiona "Ejecutar"

func main() {
fmt.Println("Hola, GoScript!")
}

Pulsa ▶ Ejecutar (o haz click en el botón). En el panel Consola verás:

1
Hola, GoScript!

Importante: todo programa GoScript debe tener una función main()
sin parámetros. Es el punto de entrada.


5. Variables y tipos

Tipos primitivos

Tipo Descripción Ejemplos de literal
int Entero con signo. 0, 42, -7
float64 Número con decimales. 3.14, 0.5, -2.0
string Texto entre comillas dobles. "Hola", "línea 1\nlínea 2"
bool Booleano. true, false
rune Carácter Unicode. 'A', 'ñ', '\n'
nil Ausencia de valor. nil

Declaraciones soportadas

GoScript admite tres estilos de declaración para que la sintaxis sea
flexible:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func main() {
// 1) Estilo Go con var:
var edad int = 25
var pi float64 = 3.1416
var saludo string // sin valor → "" por defecto

// 2) Inferencia con :=
nombre := "Ana"
activo := true

// 3) Estilo C: Tipo nombre = valor
int contador = 0
float64 precio = 99.99
string ciudad = "Guatemala"
bool admin = false

fmt.Println(edad, pi, saludo, nombre, activo, contador, precio, ciudad, admin)
}

Valor por defecto

Si declaras una variable con var x T sin valor:

Tipo Valor por defecto
int, rune 0
float64 0.0
string ""
bool false
slice nil
struct nil

Reglas de coerción al asignar

Sólo hay una promoción automática: int o runefloat64. Cualquier
otra mezcla de tipos al asignar produce un error semántico. Por ejemplo:

1
2
var x float64 = 7         // OK: 7 (int) se promueve a 7.0
var s string = 42 // ERROR: int → string no es automático

Para convertir entre tipos numéricos y strings usa los built-ins
strconv.Atoi y strconv.ParseFloat (sección 11).


6. Operadores

Aritméticos

+, -, *, /, %. Reglas resumidas:

  • Cualquier operación con string y otro tipo en + produce un string
    (concatenación con conversión automática).
  • Si alguno de los operandos es float64, el resultado es float64.
  • int / int da int truncado. Si quieres float64 divide entre 1.0
    o convierte uno de los operandos.
  • % solo funciona entre int.
  • string * int repite la cadena ("ab" * 3 = "ababab").
  • División y módulo entre cero generan error de ejecución.

Incremento y decremento

x++ y x-- son sentencias, no expresiones. Se permiten sobre cualquier
lvalue numérico (variables, slice[i], struct.campo).

Comparación

==, !=, <, <=, >, >=. Devuelven bool. Comparan numéricos entre
sí (con promoción automática), strings entre sí, booleanos entre sí, y nil
con cualquier referencia (slice/struct).

Lógicos

&&, ||, ! solo aplican a booleanos. && y || evalúan en
cortocircuito:

1
2
3
if x != nil && x.activo {
// x.activo no se evalúa si x es nil
}

Asignación compuesta

+= y -= modifican un lvalue en su lugar:

1
2
3
4
total := 0
for _, v := range valores {
total += v
}

Precedencia (de menor a mayor)

1
2
3
4
5
6
7
||
&&
== !=
< <= > >=
+ -
* / %
unario - !

Usa paréntesis cuando dudes; el AST refleja exactamente lo que escribiste.


7. Control de flujo

if / else if / else

1
2
3
4
5
6
7
if edad >= 18 {
fmt.Println("Mayor de edad")
} else if edad >= 13 {
fmt.Println("Adolescente")
} else {
fmt.Println("Niño")
}

La condición debe ser un bool. No hay conversión automática.

switch

1
2
3
4
5
6
7
8
switch dia {
case 1, 2, 3, 4, 5:
fmt.Println("Día laboral")
case 6, 7:
fmt.Println("Fin de semana")
default:
fmt.Println("Día inválido")
}

A diferencia de C, no hay fall-through: cada case termina implícitamente
después de ejecutar su cuerpo.

for (cuatro variantes)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 1) Infinito
for {
if listo { break }
}

// 2) Estilo while
for x < 10 {
x++
}

// 3) Clásico con init / cond / post
for i := 0; i < 10; i++ {
fmt.Println(i)
}

// 4) For-range sobre slices
for i, v := range numeros {
fmt.Println(i, v)
}

// 4b) For-range solo con índice
for i := range numeros {
fmt.Println(i)
}

// 4c) For-range sobre string (i = posición, c = rune)
for i, c := range "Hola" {
fmt.Println(i, c)
}

break, continue, return

  • break sale del for o switch envolvente más cercano.
  • continue salta al siguiente ciclo del for envolvente.
  • return devuelve de la función actual; con o sin valor según la firma.

Usar cualquiera de los tres fuera de su contexto válido produce un error
semántico.


8. Funciones

Declaración

1
2
3
4
5
6
7
8
9
10
11
12
func sumar(a int, b int) int {
return a + b
}

func saludar(nombre string) { // sin valor de retorno
fmt.Println("Hola, " + nombre)
}

func main() {
fmt.Println(sumar(3, 4))
saludar("Mynor")
}

Recursión

Las funciones pueden llamarse a sí mismas sin restricciones:

1
2
3
4
5
6
func factorial(n int) int {
if n <= 1 {
return 1
}
return n * factorial(n - 1)
}

Slices como argumento o retorno

1
2
3
4
5
6
7
func duplicar(valores []int) []int {
salida := []int{}
for _, v := range valores {
salida = append(salida, v * 2)
}
return salida
}

Reglas

  • Cada función define un nuevo ámbito; sus parámetros se declaran como
    variables locales.
  • El padre del entorno de una función es siempre el global; no se capturan
    variables del ámbito del llamador.
  • Sólo se puede devolver un valor (o ninguno).
  • Si una función con tipo de retorno termina sin return, devolverá el
    valor por defecto del tipo.

9. Slices

Un slice es una secuencia indexada y dinámica de elementos del mismo tipo.

Creación

1
2
3
4
5
6
7
8
9
10
// Forma estándar: tipo seguido de los elementos
nums := []int{10, 20, 30}
nombres := []string{"Ana", "Luis", "Marta"}

// Slice vacío
vacios := []int{}

// Estilo C: declaración con tipo a la izquierda
[]int datos = {1, 2, 3, 4, 5}
[]string vocales = {"a", "e", "i", "o", "u"}

Acceso, modificación y len

1
2
3
fmt.Println(nums[0])     // 10
nums[1] = 99 // ahora nums = [10 99 30]
fmt.Println(len(nums)) // 3

Slices multidimensionales

1
2
3
4
5
6
7
8
matriz := [][]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}

fmt.Println(matriz[1][2]) // 6
matriz[0][0] = 99

El elemento abreviado {1, 2, 3} dentro de un slice multidimensional
hereda el tipo del slice padre. La coma final en la última línea es
opcional pero permitida.

append

Agrega uno o más elementos al final y devuelve un nuevo slice:

1
2
nums = append(nums, 40)
nums = append(nums, 50, 60, 70)

Importante: append no muta el slice original; siempre asigna el resultado.

for-range

1
2
3
for i, v := range nums {
fmt.Println(i, v)
}

10. Structs

Los structs son tipos compuestos con campos nombrados, declarados a nivel
global (fuera de cualquier función).

Declaración

1
2
3
4
5
6
7
8
9
10
11
struct Persona {
string nombre;
int edad;
bool activo;
}

struct Equipo {
string nombre;
Persona capitan;
int puntos;
}

El punto y coma al final de cada campo es opcional.

Instanciación

GoScript admite dos sintaxis:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func main() {
// 1) Estilo Go con nombre del tipo:
ana := Persona{nombre: "Ana", edad: 25, activo: true}

// 2) Estilo C, declarando con tipo a la izquierda:
Persona luis = {nombre: "Luis", edad: 30, activo: false}

// Structs anidados:
Equipo rojos = {
nombre: "Rojos",
capitan: ana,
puntos: 0,
}
}

Lectura y mutación de campos

1
2
3
fmt.Println(ana.nombre)       // Ana
ana.edad = 26
rojos.capitan.activo = false // mutación anidada

Acceso a structs anidados

GoScript soporta cualquier nivel de anidamiento. Cada acceso intermedio
devuelve una referencia al sub-struct, por lo que las mutaciones se
reflejan correctamente en el padre:

1
rojos.capitan.edad = 27       // se ve también en ana.edad

11. Funciones embebidas

Función Descripción Ejemplo
fmt.Println(...) Imprime los argumentos separados por espacios y agrega \n. fmt.Println("x =", x)
fmt.Print(...) Igual a Println pero sin salto de línea. fmt.Print("Cargando...")
strconv.Atoi(s) Convierte un string a int. Devuelve 0 si falla. n := strconv.Atoi("42")
strconv.ParseFloat(s) Convierte un string a float64. pi := strconv.ParseFloat("3.14")
reflect.TypeOf(v) Devuelve el nombre del tipo de v como string. fmt.Println(reflect.TypeOf(3.14))float64
len(v) Longitud de un string o slice. len("hola")4
append(s, x...) Devuelve un slice nuevo con los elementos agregados al final. s = append(s, 1, 2, 3)
slices.Index(s, x) Devuelve la posición de x en s, o -1. slices.Index([]int{2,4,6}, 4)1
strings.Join(s, sep) Une un []string usando el separador. strings.Join([]string{"a","b"}, "-")"a-b"

12. Reportes

Después de pulsar ▶ Ejecutar, el panel lateral muestra cuatro vistas:

Consola

Aquí aparece todo lo que tu programa escribe con fmt.Print y fmt.Println.

Errores

Tabla con todos los errores detectados, codificados por color:

  • Rojo (Léxico) — el lexer encontró un carácter desconocido.
  • Amarillo (Sintáctico) — el parser no pudo entender una construcción.
  • Azul (Semántico) — el intérprete detectó una incoherencia en tiempo
    de ejecución (variable no declarada, división entre cero, tipos
    incompatibles, etc.).

Botón Descargar HTML: guarda un archivo autocontenido con el reporte.

Tabla de Símbolos

Lista todos los identificadores observados durante la ejecución (variables,
parámetros, funciones, structs) con su tipo, valor, ámbito y ubicación.

Botón Descargar HTML: guarda la tabla como archivo independiente.

AST

Diagrama interactivo del árbol de sintaxis abstracta producido por el
parser. Cada nodo está coloreado por categoría:

  • Verde: declaraciones y literales.
  • Azul: sentencias.
  • Naranja: operadores.
  • Morado: llamadas a función.

Botones Descargar SVG y Descargar DOT te permiten exportar el grafo
para incluirlo en informes o procesarlo con Graphviz fuera del IDE.


13. Atajos de teclado

Acción Mac Windows / Linux
Guardar pestaña activa ⌘ + S Ctrl + S
Nueva pestaña ⌘ + N Ctrl + N
Cerrar pestaña activa ⌘ + W Ctrl + W
Click central sobre pestaña Cerrar

Cuidado con Ctrl + Shift + N: el IDE no captura esa combinación
porque algunos navegadores la usan para abrir ventana de incógnito.


14. Solución de problemas

“Error de red” al ejecutar

El frontend no pudo contactar al backend. Verifica que:

  1. El backend esté corriendo (npm run dev en la carpeta backend/).
  2. La URL del API que aparece en el pie del IDE sea correcta.
  3. No haya un firewall bloqueando el puerto 3001.

“Error sintáctico cerca de X”

El parser encontró un token que no esperaba. Causas comunes:

  • Olvidar el () después del nombre de una función al llamarla.
  • Mezclar declaraciones con := y = (la primera declara, la segunda asigna).
  • Olvidar el tipo en una declaración estilo C: debe ser int x = 5, no
    x int = 5.
  • Usar { directamente como cuerpo del if sin la condición previa.

“La variable X no ha sido declarada”

Estás usando una variable que nunca se declaró en este ámbito ni en uno
padre. Recuerda que cada función tiene como padre el ámbito global, no
el del llamador.

“No se puede asignar T1 a T2”

Estás intentando una conversión que GoScript no hace automáticamente. La
única promoción implícita es int o runefloat64. Para todas las
demás usa strconv.Atoi, strconv.ParseFloat o concatenación con string.

El AST no se muestra

Verifica que la ejecución haya terminado sin errores fatales. Si hay un
error sintáctico el AST queda vacío. También revisa la consola del
navegador por si hubo un fallo al cargar la librería de Graphviz.


15. Limitaciones

GoScript es un subconjunto didáctico de Go. No soporta:

  • Closures ni captura de variables externas en funciones.
  • Funciones de orden superior (no se pueden pasar funciones como argumentos).
  • Múltiples valores de retorno en una sola función.
  • Maps (map[K]V) ni canales (chan T).
  • Goroutines ni select.
  • Punteros (*T) ni operador &.
  • Interfaces ni métodos asociados a structs.
  • Imports: los nombres fmt, strconv, etc. son prefijos sintácticos
    reservados, no módulos importables.

Si tu programa necesita alguna de estas características, deberás
adaptarlo a las construcciones disponibles en GoScript.


¿Necesitas más detalles sobre el lenguaje? Consulta también:

avatar
Mynor Cifuentes
Mynor's personal blog
Follow Me
Announcement
Todo el código fuente compartido en este blog se encuentra bajo la licencia MIT. Puedes usar, modificar y distribuir el código para cualquier propósito, siempre y cuando incluyas la nota de copyright y la licencia original.