-
Es posible tener más de un archivo abierto simultáneamente. Ver Sistema de Pestañas.
- Declaración de Variables
var id: type = value
var id: [[type]] = value
var id: [type] = value
var id: type?
var id = value
- Declaración de Métodos y Funciones
func id((externName|_)? param1 : type,(externName|_)? param2: type, ... (externName|_)? paramN: type) -> type {
//instrucciones
return expression
}
func id((externName|_)? param1 : type,(externName|_)? param2: type, ... (externName|_)? paramN: type) {
//instrucciones
}
func id() -> type {
//instrucciones
return expression
}
func id() {
//instrucciones
}
- Ciclos
for id in limInf ... limSup {
//instrucciones
}
for id in id {
//instrucciones
}
while condición {
//instrucciones
}
- Estructuras de Control
//if else if //if else //if
if condicion { if condicion { if condicion {
//instrucciones //instrucciones //instrucciones
} } }
else if condicion { else {
//instrucciones //instrucciones
} }
...
else {
//instrucciones
}
//switch
switch expresion {
case expresion:
//instrucciones
case expresion:
case expresion:
...
case expresion:
//instrucciones
default:
//instrucciones
}
- Casteo
var id: type = type(expresion)
var id = type(expresion)
type Type int
const (
INT Type = iota
FLOAT
STRING
BOOLEAN
CHAR
NIL
VECTOR
MATRIX
)
+ | INT | DOUBLE | STRING |
---|---|---|---|
INT | INT | DOUBLE | NIL |
DOUBLE | DOUBLE | DOUBLE | NIL |
STRING | NIL | NIL | STRING |
- | INT | DOUBLE |
---|---|---|
INT | INT | DOUBLE |
DOUBLE | DOUBLE | DOUBLE |
* | INT | DOUBLE |
---|---|---|
INT | INT | DOUBLE |
DOUBLE | DOUBLE | DOUBLE |
/ | INT | DOUBLE |
---|---|---|
INT | INT | DOUBLE |
DOUBLE | DOUBLE | DOUBLE |
% | INT |
---|---|
INT | INT |
Es el tipo que retorna cada Expresión para tener referencia, no solo del valor sino también del tipo de dato resultante.
type ReturnType struct {
Value interface{}
Type Type
}
-
Se implementó la clase Expression que es la clase padre de todas aquellas funcionalidades del lenguaje TypeWise que retornan un valor, tales como:
- Llamada a Función
- Acceso a Variables
- Primitivas
- Posiciones de Vectores
- Posiciones de Matrices
- Sentencia 'Return'
- Operaciones
- Aritméticas
- Relacionales
- Lógicas
- Funciones Embebidas
- String
- Int
- Float
- Casteo
Es necesario que cada expresión tenga una referencia de los entornos globales relativamente, ya que desde un bloque de código interno se puede acceder a las variables y funciones de los entornos más globales.
type Expression interface {
LineN() int
ColumnN() int
Exec(env *env.Env) *utils.ReturnType
}
- Se implementó la clase Instruction que es la clase padre de todas aquellas funcionalidades del lenguaje TypeWise que no retornan un valor, tales como:
- Función Append propia de los Vectores
- Inicialización de Variables
- Primitivas
- Vectores
- Matrices
- Sentencias de Transferencia
- Continue
- Break
- Reasignación de Valores
- Variables Primitivas
- Posiciones de Vectores
- Posiciones de Matrices
- Declaración de Funciones
- Estructuras de Control
- If
- Else If
- Else
- Guard
- Switch Case
- Ciclos
- For
- While
- Bloques de Instrucciones
Es necesario que cada instrucción tenga una referencia de los entornos globales relativamente, ya que desde un bloque de código interno se puede acceder a las variables y funciones de los entornos más globales.
type Instruction interface {
LineN() int
ColumnN() int
Exec(env *env.Env) *utils.ReturnType
}
En el entorno se guarda la referencia hacia cada variable, arreglo, método o función declarada.
- Para declarar una variable nueva primero se debe verificar que no exista previamente, en el Map de identificadores del entorno, una variable con el mismo nombre sin importar el tipo.
func (env *Env) SaveID(isVariable bool, id string, value *utils.ReturnType, Type utils.Type, line, column int) bool {
if _, exists := (*env.Ids)[id]; !exists {
(*env.Ids)[id] = &Symbol{IsVariable: isVariable, IsPrimitive: true, Value: value, Id: id, Type: Type}
SymTable.Push(NewSymTab(line, column, isVariable, true, id, env.Name, Type, utils.NIL))
return true
}
env.SetError("Redeclaración de variable existente", line, column)
return false
}
- Para declarar un vector nuevo de n dimensiones primero se debe verificar que no exista o esté declarada previamente, en el Map de identificadores del entorno, una variable con el mismo nombre sin importar el tipo.
func (env *Env) SaveArray(isVariable bool, id string, value interface{}, Type utils.Type, line, column int) bool {
if _, exists := (*env.Ids)[id]; !exists {
(*env.Ids)[id] = &Symbol{IsVariable: isVariable, IsPrimitive: false, Value: value, Id: id, Type: utils.VECTOR, ArrType: Type}
SymTable.Push(NewSymTab(line, column, isVariable, false, id, env.Name, utils.VECTOR, Type))
return true
}
env.SetError("Redeclaración de variable existente", line, column)
return false
}
- Para obtener el valor de una variable es necesario hacer una búsqueda en el Map de identificadores de cada entorno comenzando por el entorno local. En caso de no encontrar el identificador en el entorno local es necesario ascender de entornos hasta encontrar el identificador de la variable, si es que se declaró previamente.
func (env *Env) GetValueID(id string, line, column int) *Symbol {
var current *Env = env
for current != nil {
if _, exists := (*current.Ids)[id]; exists {
return (*current.Ids)[id]
}
current = current.previous
}
current.SetError(fmt.Sprintf("Acceso a variable inexistente. '%s'", id), line, column)
return nil
}
- Para obtener el valor de una posición de un vector es necesario hacer una búsqueda en el Map de identificadores de cada entorno comenzando por el entorno local. En caso de no encontrar el identificador en el entorno local es necesario ascender de entornos hasta encontrar el identificador de la variable, si es que se declaró previamente. Si existe se utiliza la lista de índices que fue enviada como parámetro para encontrar una posición específica del vector.
func (v *Vector) GetPosition(env *env.Env, indexs []int, line, column int) interface{} {
if len(indexs) > v.Dims {
env.SetError("Las dimensiones no coinciden con las del vector", line, column)
return nil
}
if len(indexs) == 1 {
if v.IsMatrix {
if indexs[0] >= 0 && indexs[0] < len(v.Vectors) {
return v.Vectors[indexs[0]]
}
env.SetError("Índices fuera de rango", line, column)
return nil
}
if indexs[0] >= 0 && indexs[0] < len(v.Values) {
return v.Values[indexs[0]]
}
env.SetError("Índices fuera de rango", line, column)
return nil
}
if indexs[0] >= 0 && indexs[0] < len(v.Vectors) {
return v.Vectors[indexs[0]].GetPosition(env, indexs[1:], line, column)
}
env.SetError("Índices fuera de rango", line, column)
return nil
}
- Para reasignar un nuevo valor a una variable previamente declarada es necesario hacer una búsqueda en el Map de identificadores de cada entorno comenzando por el entorno local. En caso de no encontrar el identificador en el entorno local es necesario ascender de entornos hasta encontrar el identificador de la variable, si es que se declaró previamente. Si existe se le asigna el nuevo valor
func (env *Env) ReasignID(id string, value *utils.ReturnType, line, column int) bool {
var current *Env = env
for current != nil {
if _, exists := (*current.Ids)[id]; exists {
if (*current.Ids)[id].IsVariable {
if (*current.Ids)[id].Type == value.Type || (*current.Ids)[id].Type == utils.STRING && value.Type == utils.CHAR || (*current.Ids)[id].Type == utils.FLOAT && value.Type == utils.INT {
(*current.Ids)[id].Value = value
return true
}
current.SetError(fmt.Sprintf("Los tipos no coinciden en la asignación. Intenta asignar un \"%v\" a un \"%v\"", current.getType(value.Type), current.getType((*current.Ids)[id].Type)), line, column)
return false
}
current.SetError("Resignación de valor a constante", line, column)
return false
}
current = current.previous
}
current.SetError("Resignación de valor a variable inexistente", line, column)
return false
}
- Para reasignar un nuevo valor a una posición de un vector es necesario hacer una búsqueda en el Map de identificadores de cada entorno comenzando por el entorno local. En caso de no encontrar el identificador en el entorno local es necesario ascender de entornos hasta encontrar el identificador de la variable, si es que se declaró previamente. Si existe se utiliza la lista de índices que fue enviada como parámetro para encontrar una posición específica del vector y reasignarle el nuevo valor.
func (v *Vector) SetValuePosition(env *env.Env, indexs []int, newValue interfaces.Expression, line, column int) bool {
if len(indexs) > v.Dims {
env.SetError("Las dimensiones no coinciden con las del vector", line, column)
return false
}
if len(indexs) == 1 {
if v.IsMatrix {
if indexs[0] >= 0 && indexs[0] < len(v.Vectors) {
env.SetError("Solo puede modificarse un elemento a la vez en un vector", line, column)
return false
}
env.SetError("Índices fuera de rango", line, column)
return false
}
if indexs[0] >= 0 && indexs[0] < len(v.Values) {
if v.Values[indexs[0]].Type == newValue.Exec(env).Type {
v.Elements[indexs[0]] = newValue
v.Values[indexs[0]] = newValue.Exec(env)
return true
}
env.SetError("El tipo del nuevo valor no coincide con el que almacena el vector", line, column)
return false
}
env.SetError("Índices fuera de rango", line, column)
return false
}
if indexs[0] >= 0 && indexs[0] < len(v.Vectors) {
return v.Vectors[indexs[0]].SetValuePosition(env, indexs[1:], newValue, line, column)
}
env.SetError("Índices fuera de rango", line, column)
return false
}
- Para insertar un nuevo valor en una lista es necesario hacer una búsqueda en el Map de identificadores de cada entorno comenzando por el entorno local. En caso de no encontrar el identificador en el entorno local es necesario ascender de entornos hasta encontrar el identificador de la variable, si es que se declaró previamente. Si existe se inserta el nuevo valor al vector.
func (a *Append) Exec(env *env.Env) *utils.ReturnType {
vec := env.GetValueID(a.ID, a.Line, a.Column)
if vec.Type == utils.VECTOR {
newValue := a.Exp.Exec(env)
if newValue.Type == vec.ArrType {
vec.Value.(*vector.Vector).Elements = append(vec.Value.(*vector.Vector).Elements, a.Exp)
vec.Value.(*vector.Vector).Values = append(vec.Value.(*vector.Vector).Values, a.Exp.Exec(env))
vec.Value.(*vector.Vector).Length += 1
return nil
}
env.SetError("El tipo de dato del nuevo valor no es el mismo que almacena el vector", a.Line, a.Column)
return nil
}
env.SetError("El método 'append' es exclusivo de vectores", a.Line, a.Column)
return nil
}
- Para declarar una función o método nueva primero se debe hacer una búsqueda en el Map de funciones del entorno global. En caso de no encontrar el identificador de la función en el entorno global se guarda la nueva función.
func (env *Env) SaveFunction(id string, Func *interface{}, Type utils.Type, line, column int) bool {
if _, exists := (*env.Functions)[id]; !exists {
(*env.Functions)[id] = Func
SymTable.Push(NewSymTab(line, column, false, false, id, env.Name, Type, utils.NIL))
return true
}
env.SetError("Redefinición de función existente", line, column)
return false
}
- Para obtener una función o método, para posteriormente ejecutarla, primero se debe hacer una búsqueda en el Map de funciones del entorno global. En caso de no encontrar el identificador de la función en el entorno global no se retorna nada.
func (env *Env) GetFunction(id string, line, column int) *interface{} {
if _, exists := (*env.Functions)[id]; exists {
return (*env.Functions)[id]
}
env.SetError("Acceso a función inexistente", line, column)
return nil
}
- Para obtener el entorno global es necesario ir ascendiendo desde el entorno local actual hasta que ya no exista un entorno global relativo del entorno actual.
func (env *Env) GetGlobal() *Env {
current := env
for current.previous != nil {
current = current.previous
}
return current
}