Julia es un lenguaje de programación bastante reciente que le interesa a científicos de datos, estadísticos y analistas financieros. Este cuenta con distintas características atractivas para los programadores. Aún así, Julia al ser un lenguaje de programación bastante reciente, hay muy pocos lugares donde se pueda probar su sintaxis de manera sencilla. Es por eso que se desarrollo JOLC, un lenguaje de programación basado en Julia que se podrá programar desde el navegador.
A continuación, se detalla la sintaxis que tendrá JOLC. Además de algunos archivos de entrada de prueba que podrán probar para familiarizarse con la sintaxis.
Los comentarios pueden ser:
- Una línea (#)
- Múltiples líneas (#= ... =#)
# Esto es un comentario de una sola línea
#=
Esto es un
comentario de
múltiples líneas
=#
JOLC aceptará distintos tipos de datos con los que cuenta Julia. Entre ellos se aceptarán:
Se representa con la palabra reservada Nothing
, la cual indica que no existe ningún valor.
Valores numéricos enteros. Por ejemplo: 3
, 2
, -1
, -100
.
Valores númericos con punto flotante. Por ejemplo: 3.1415
, 2.7182
, 0.5
.
Los valores booleanos únicamente pueden ser true
o false
.
Estos son literales de carateres, se definen con comillas simples. Por ejemplo: 'a'
, 'b'
, 'z'
.
Estos representan cadenas de texto, se definen con comillas dobles. Por ejemplo: "Hola"
, "Mundo"
, "!"
.
Los Strings también cuentan con operaciones especiales que se pueden realizar con estos. Se detalla más adelante en la sección de Expresiones.
Estos son un conjunto de valores indexados entre 1 hasta n, que pueden ser de diferentes tipos. Por ejemplo:
[10, 20, 30, 40]
["Hola", "Mundo"]
['a', 2.0, 5, ["Hola", "Mundo"]].
Los arreglos cuentan con distintas operaciones que se detallarán en la sección de Arreglos.
Estos son tipos compuestos definidos por el programador. Existen 2 tipos de Struct, aquellos que son mutables y los inmutables. Para la declaración de struct inmutables se realizar de la siguiente manera:
struct NOMBRE_STRUCT
LISTA_ATRIBUTOS
end;
Para declarar un Struct mutable se agrega la palabra reservada mutable:
mutable struct NOMBRE_STRUCT
LISTA_ATRIBUTOS
end;
Y para crear una variable con nuestro Struct, se escribe:
ID = NOMBRE_STRUCT(LISTA_VALORES);
Un ejemplo de creación de struct podría ser:
struct Rectangulo
base::Int64;
altura;
end;
Noten que en los atributos pueden o no llevar tipo de dato.
En la sección de Structs se detallará más al respecto de estos.
JOLC acepta operaciones aritmeticas, relacionales y logicas de la siguiente forma:
Entre las operaciones aritmeticas disponibles vamos a encontrar las siguientes:
- Suma: La suma de dos expresiones se define por el símbolo
+
- Resta: La resta de dos expresiones y la negación de una expresión aritmetica se define por el símbolo
-
- Multiplicación: La multiplicación de dos expresiones se define por el símbolo
*
- División: La división de dos expresiones se define por el símbolo
/
- Modulo: El modulo entre dos expresiones se define por el símbolo
%
- Potencia: La potenciación de una expresión se define por el símbolo
^
- Nativas: JOLC posee 6 funciones nativas para la resolución de expresiones, entre ellas se encuentran:
- log10: Resuelve el logaritmo de base 10 del numero que se ingrese
- log: Recibe como parametro la base y el numero del cual se desea obtener el logaritmo con la base especificada. Ejemplo:
log(2,4)
- sin: Resuelve la función seno del número que se ingrese
- cos: Resuelve la función coseno del numero que se ingrese
- tan: Resuelve la función tangente del numero que se ingrese
- sqrt: Resuelve la raiz cuadrada del numero que se ingrese
#Se expresa de la siguiente manera:
sin(134)
log10(100)
cos(var1)
tan(12)
sqrt(16)
Entre las operaciones relacionales disponibles vamos a encontrar las siguientes:
- Igualdad: Esta se define por el símbolo
==
- Diferenciación: Esta se define por el símbolo
!=
- Mayor que: Esta se define por el símbolo
>
- Menor que: Esta se define por el símbolo
<
- Mayor o igual que: Esta se define por el símbolo
>=
- Menor o igual que: Esta se define por el símbolo
<=
Entre las operaciones lógicas disponibles vamos a encontrar las siguientes:
- AND: Esta se define por el símbolo
&&
- OR: Esta se define por el símbolo
||
- NOT: Esta se define por el símbolo
!
Entre las operaciones con cadenas (strings) vamos a encontrar las siguientes:
- Concatenación: La unión de dos cadenas de texto se define por el símbolo
*
"para" * "caidismo" = "paracaidismo"
- Repetición: Permite que una cadena de texto se repita cierto número de veces, esta se define por el símbolo
^
"Cadena"^3 = "CadenaCadenaCadena"
- Acceso a una pocisión: El acceso a un elemento de una cadena se define de la siguiente manera:
string[posición]
, el cual devolvera el caracter correspondiente a esa posiciónanimal = "Tigre"; println(animal[2]); #i
- Acceso a una porción: El acceso a una porción de una cadena se define de la siguiente manera:
string[inicial:final]
, el cual devolvera la cadena correspondiente al intervalo definido.animal = "Tigre"; println(animal[2:4]); #igr
- Tamaño de una cadena: La obtención del número de elementos de una cadena se define por la función
length(cadena)
animal = "Tigre"; println(length(animal)); #5
- Cadena en mayusculas: Una cadena puede ser convertida a mayusculas con la utilización de la función
uppercase(cadena)
animal = "Tigre"; println(uppercase(animal)); #TIGRE
- Cadena en minusculas: Una cadena puede ser convertida a mayusculas con la utilización de la función
lowercase(cadena)
animal = "Tigre"; println(lowercase(animal)); #tigre
El operador ternario es utilizado cuando se necesita entre diferentes expresiones a travez de una condición
(EXPRESIÓN RELACIONAL O LOGICA) ? RESULTADO SI ES VERDADERO : RESULTADO SI ES FALSO
Ejemplo:
respuesta = edad >= 50 ? "Puede vacunarse" : "No puede vacunarse";
println(animal == "Perro" ? 15 : 10);
JOLC contará con varias instrucciones para su ejecución, cada instrucción debe terminar con un punto y coma (;
). Las instrucciones que JOLC acepta son:
JOLC cuenta con 2 distintas instrucciones de imprimir.
print(expresión); # Esta imprime sin realizar un salto de línea
println(expresión); # Esta imprime realizando un salto de línea
Para imprimir más de un valor por línea, se puede imprimir una secuencia de valores separados por comas. También dentro de las cadenas se pueden colocar cualquier expresión utilizando el operador $
. Por ejemplo:
println("+", "-"); # Imprime + -
print("El resultado de 2 + 2 es $(2 + 2)"); # Imprime El resultado de 2 + 2 es 4
println("$a $(b[1])"); # Imprime el valor de a y el valor de b[1]
JOLC también tiene la opción de imprimir arreglos y struct. Por ejemplo:
a = [0, 1, 2];
println(a); # Imprime [0, 1, 2]
s = Hora(10, 30);
print(s); # Imprime Hora(10, 30)
JOLC permite la declaración y asignación de variables, las variables pueden cambiar su tipo de dato en cualquier momento
- Declaración: JOLC permite declarar variables de dos maneras:
ID = Expresión ::TIPO;
ó
ID = Expresión;
Ejemplo:
x = (3*5)::Int64;
y = (10/4)::Float64;
str = "Saludo"::String;
var1 = true;
Nótese que la expresión ::TIPO
es opcional.
- Asignación: JOLC permite asignar valores a variables existentes de la siguiente manera:
ID = Expresión;
Ejemplo:
var1 = "Adios";
v = 89 - 9;
- global y local:
JOLC permite definir el uso de variables globales o locales a travez de las palabras reservadas
global
ylocal
, esto quiere decir que, si una variable es declara en el entorno global y se le quiere asignar un nuevo valor dentro de una función se debe de utilizar la palabraglobal
:Si dentro de un ciclo se busca crear una nueva variable con un id igual a una variable en un entorno externo se usa la palabrax = 8200::Int64; function suma(a,b) global x = a + b; end;
local
:x = 15::Int64; function numero() local x = 80; #local de la funcion y = 0; while (y < 10) local x = 9; #local del ciclo y = y + 1; println(x) #9 end; println(x) #80 end; numero(); println(x) #15
Una llamada a función es como un desvío en el flujo de la ejecución. En lugar de pasar a la siguiente sentencia, el flujo salta al cuerpo de la función, ejecuta esta y regresa para continuar después de la llamada a la función.
Para llamar a una función se realiza de la siguiente manera:
NOMBRE_FUNCION(LISTA_PARAMETROS);
Ejemplo:
ordenamiento(arr1,arr2);
imprimirLista(lista);
nuevaLinea();
Si la función cuenta con más de un parámetro estos se separan por medio de ,
. Además es importante tener en cuenta que cuando se pasa un arreglo o struct como argumento de una función, en realidad se pasa una referencia de este. Por lo que cualquier cambio que se realice al parámetro, se podrá observar después de salir de la función.
Las llamadas a funciones también se pueden utilizar en expresiones, debido a que existen funciones que retornan un valor.
JOLC utiliza diversas funciones nativas para sus expresiones, estas son:
- Parse: Toma una cadena y la convierte al tipo de numero que se le indice si es posible.
parse(Int64,"8200")
ó
parse(Float64,"3.13159")
- Trunc: Convierte un número flotante a un número entero sin redondearlo
trunc(Int64, 3.99999) # retorna 3
- Float: Convierte un número entero a un número flotante
float(34) # retorna 34.0
- String: Convierte el argumento en una cadena, puede usarse en numeros y en arreglos
string(45.87) # retorna "45.87"
string([1,2,3]) # retorna "[1,2,3]"
- typeof: Muestra el tipo del argumento
typeof(5 * 5) #Int64
Las funcioens son secuencias de sentencias que ejecuta una operación que nosotros deseamos. Cuando se crea una función se especifica su nombre y secuencia de sentencias. Luego, ya se puede llamar a estas usando su nombre y los parámetros solicitados. Se definen las funciones en JOLC así:
function NOMBRE_FUNCION(LISTA_PARAMETROS)
LISTA_INSTRUCCIONES
end;
Las instrucciones se separarán utilizando ;
. Por ejemplo:
function imprimirHola()
println("Hola");
println("Hola");
end;
Además, los parámetros de las funciones vendrán separadas por ,
y podrán o no llevar tipo de dato.
function sumar(num1::Int64, num2)
return num1 + num2;
end;
Hay que tomar en cuenta que las variables y parámetros que se creen dentro de una función son locales, es decir que únicamente existen dentro de la función.
Las funciones también pueden llamarse a sí mismas. Lo que permite una gran variedad de aplicaciones en estructuras de datos y algoritmos de ordenamiento.
JOLC cuenta con sentencias condicionales, lo que permite que un bloque de codigo pueda ser o no ejecutado. Estas se definen por if
,if...else
y if...elseif
. Su estructura es la siguiente:
if CONDICION
LISTA_INTRUCCIONES
end;
if CONDICION1
LISTA_INTRUCCIONES
elseif CONDICION2
LISTA_INTRUCCIONES
else
LISTA_INTRUCCIONES
end;
Ejemplo:
if x == 8
var1 = (x + 8)::Int64;
println(sqrt(var1));
end;
if x == 8
var1 = (x + 8)::Int64;
println(sqrt(var1));
elseif x < 8
var1 = (x/3)::Float64;
println(sin(var1));
else
println("Error");
end;
JOLC cuenta con sentencias iterativas, lo que permite ejecutar repetidamente un bloque de sentencias. Existen 2 de estas, el ciclo while
y el ciclo for
.
La sentencia while
sigue la siguiente estructura:
while CONDICION
LISTA_INSTRUCCIONES
end;
Ejemplo:
while var1 < 10
println(var1);
var1 = var1 + 1;
end;
Y se ejecutará hasta que la condición del while se vuelva false. De manera más formal, el flujo de un while es el siguiente:
- Se determina si la condición es true o false.
- Si es false, se sale de la sentencia
while
y continúa la ejecución con la siguiente sentencia. - Si es true, ejecuta cada una de las sentencias en la lista de instrucciones.
La sentencia for
en JOLC puede iterar sobre tipos que son iterables. Como lo son rangos, Array, String.
Sigue la siguiente estructura:
for ID in (RANGO | STRING | ARRAY)
LISTA_INSTRUCCIONES
end;
Algunos ejemplos de for en JOLC son:
for i in 1:4 # Recorre rango de 1:4
print(i, " "); # Únicamente se recorre ascendentemente
end; # Imprime 1 2 3 4
for letra in "Hola Mundo!" # Recorre las letras de la cadena
print(letra, "-"); # Imprime H-o-l-a-M-u-n-d-o-!
end;
cadena = "OLC2";
for letra in cadena
print(letra, "-"); # Imprime O-L-C-2
end;
for animal in ["perro", "gato", "tortuga"]
println("$animal es mi favorito");
#= Imprime
perro es mi favorito
gato es mi favorito
tortuga es mi favorito
=#
end;
arr = [1,2,3,4,5]
for numero in arr[2:4]
print(numero, " ") # Imprime 2 3 4
end;
Hay que tomar en cuenta en los arreglos que también puede ser un rango de algún arreglo. Por ejemplo:
for it in a[begin:end]
# Haz algo
end;
Dentro de los ciclos también existen las sentencias de control break
y continue
. Las cuales, una termina el bucle y la otra regresa al inicio del bucle ignorando las sentencias faltantes.
Como se a mencionado JOLC cuenta con arreglos, los cuales pueden ser definidos mediante una sintaxis. Los valores de los arreglos pueden ser de cualquier tipo.
[8,true,"JOLC",[1,2,3]]
Para acceder a una posición en específico del arreglo, se debe definir una expresión que de como resultado un numero entero dentro de corchetes. los indices en JOLC inician desde el numero 1 en adelante.
arr = ["H","O","L","A"];
print(arr[1]) #H
JOLC tambien permite que se acceda a una porción de un arreglo, esto se define mediante la sintaxis begin:end
, el cual debe ir dentro de corchetes y devolvera un arreglo con los limites establecidos. Se debe tomar en cuenta que las palabras begin
y end
pueden ser utilizadas para indicar el inicio y el final del arreglo respectivamente
arr = [1,2,3,4,5,6];
print(arr[2:4]); #[2,3,4]
print(arr[begin:4]) #[1,2,3,4]
print(arr[4:end]) #[4,5,6]
JOLC permite crear una copia de un arreglo utilizando el símbolo :
, como los arreglos son mutables, es útil hacer una copia antes de realizar operaciones que las modifiquen.
arr = [1,2,3,4,5,6];
arr2 = arr[:];
arr[2] = 0;
print(arr) #[1,0,3,4,5,6]
print(arr2) #[1,2,3,4,5,6]
JOLC cuenta con 2 funciones nativas con arreglos, en los que podemos encontrar:
- Push: inserta un nuevo valor al final del arreglo, se define como:
push!(nombre_arreglo,expresión);
Ejemplo:
arr = [1,2,3,4,5,6];
push!(arr,7); # arr = [1,2,3,4,5,6,7]
- Pop: elimina y devuelve el ultimo valor de un arreglo, se define como:
pop!(nombre_arreglo,expresión);
Ejemplo:
arr = [1,2,3,4,5,6];
pop!(arr); # retorna 6, arr = [1,2,3,4,5]
Length: La obtención del tamaño de un arreglo, se define como:
length(arreglo)
Ejemplo:
arr = [1,2,3,4,5,6];
length(arr); # 6
JOLC permite la utilización del operador punto (.
) para realizar diferentes operaciones aritmeticas, trigonometricas, relaciones o cualquier otro tipo de función sobre cada valor en un arreglo.
arr = [1,2,3];
print(arr.*2) #[2,4,6]
arr2 = sin.(arr) #[0.8415, 0.9093, 0.1411]
Como se menciono en secciones anteriores, JOLC cuenta con tipos compuestos que los desarrolladores podrán definir mediante una sintaxis. Existen de tipo mutables e inmutables, con una diferencia bastante importante. Para la declaración de estos se utiliza la siguiente sintaxis:
# Struct inmutable
struct NOMBRE_STRUCT
LISTA_ATRIBUTOS
end;
# Struct mutable
mutable struct NOMBRE_STRUCT
LISTA_ATRIBUTOS
end;
Y para la creación de variables con nuestro Struct, ya sea mutable e inmutable:
ID = NOMBRE_STRUCT(LISTA_VALORES);
Siendo los valores los correspondientes a sus atributos en la lista de atributos.
Los atributos de los Struct pueden ser utilizados como parte de cualquier expresión. Para acceder a los atributos de los Struct, se utiliza la notación .
.
ID.ID
También si nosotros deseamos modificar únicamente uno de los atributos de nuestro Struct, ahí es donde entra la importancia de los dos tipos de Struct en JOLC. Los Struct que son inmutables no aceptan instrucciones de asignación en sus atributos, no se les puede cambiar el valor. En cambio, los Struct mutables si aceptan este tipo de instrucciones.
# Suponiendo que X es una variable Struct inmutable
X.atributo = expresión
ERROR !!! No se puede cambiar Struct inmutable
# Suponiendo que Y es una variable Struct mutable
Y.atributo = expresión
Otros aspectos importantes de los Structs es que estos pueden ser llamados como parámetros en las funciones y, al igual que los arreglos, se pasan por referencia. Por lo que el valor de los atributos de los Structs también cambia. Por ejemplo:
mutable struct Estructura
x;
end;
function cambiarAtributo(s)
s.x = 10;
end;
a = Estructura(0);
println(a); # Imprime 'Estructura(0)'
println(a.x); # Imprime 0
cambiarAtributo(a);
println(a); # Imprime 'Estructura(10)'
println(a.x); # Imprime 10
Hay que tomar en cuenta de que si la estructura fuera de tipo inmutable, esta mostraría un error por la asignación.
Se debe de tomar en cuenta que los Struct se pueden utilizar como retorno de una función.