# Organización y estructura del programa ## Ámbitos Todos los programas en DKL tienen 3 ámbitos: - Global. Las variables declaradas como globales están disponibles en cualquier ámbito - Principal. El ámbito principal del programa consiste en el código fuera de las funciones definidas por el programador. - De función. El correspondiente al bloque de código de una función definida por el programador en particular. ```DKL #include "dkli.dkh" #! program { funcion1:: { //Ámbito de función a=3 //Variable local al ámbito de la función } //Ámbito principal @a=1 //Variable global a =2 //Variable local al ámbito principal } ``` ## Espacios de nombres y bloques de código Todo archivo DKL es un árbol y debe tener un por tanto un elemento raíz. Si se escribe un programa imperativo deberá incluirse el cuerpo de código dentro de un elemento program, module o codeblock. Los elementos program, module y codeblock sirven como nodo raíz y contenedor del ámbito principal o delimitan el alcance de un espacio de nombres. ```DKL program "mi programa" { //Código aquí } ``` Es equivalente a: ```DKL module "mi programa" { //Código aquí } codeblock "mi programa" { } ``` También es válido: ```DKL module "modulo raíz" { funcion1:: { //Este es el ámbito de una función codeblock ":espacion_de_nombres" { } } //Ámbito principal module "modulo interno" { //También aquí es el ámbito principal } } ``` La cadena de texto que sique a la declaración de module, program o codeblock es opcional, pero además de proporcionar una descripción, también sirve para indicar un espacio de nombres al bloque de código. Si no se indica explícitamente un espacio de nombres, se asume que las funciones pertenecen al espacio de nombres global de la instancia de ejecución. Cuando se realizan inclusiones (#include o include) el código se inserta en la ubicación de la sentencia o directiva. El código de un bloque module, program o codeblock pertenece al ámbito en que se encuentra, DKL no tiene ámbitos aislados para estos tipos de bloques. ### Declaración de espacios de nombres Un espacio de nombres ayuda a organizar y clasificar código, es una característica muy útil cuando se tienen muchas funciones. #### Sintaxis de especificación de espacios de nombres en bloques de código ``` program "descripcion:espacion_de_nombres" { } module "descripcion:espacion_de_nombres" { } codeblock "descripcion:espacion_de_nombres" { } ``` El espacio de nombres es la cadena indicada después del caracter ':'. Ejemplo: ``` module "Gestión de inventarios, movimientos:inventarios.movimientos" { entradas::&datos { } salidas::&datos { } traspasos::&datos { } } ``` Cuando se indica un espacio de nombres en un bloque (program, module o codeblock), los nombres de las funciones incorporarán automáticamente como prefijo la cadena de dicho espacio de nombres delimitado por un punto '.', por lo que con base en el ejemplo anterior, las funciones están nombradas realmente como: ```inventarios.movimientos.entradas``` ```inventarios.movimientos.salidas``` y ```inventarios.movimientos.traspasos```. Si una función incorpora en el inicio de su nombre el espacio de nombres del bloque en el que está declarada, no se concatenará dicho espacio de nombres. ``` module "Gestión de inventarios, movimientos:inventarios.movimientos" { inventarios.movimientos.atipicos::&datos { //Nombre completo de la función: inventarios.movimientos.atipicos } entradas::&datos { //Nombre completo de la función: inventarios.movimientos.entradas } extemporaneos.devoluciones::&datos { //Nombre completo de la función: inventarios.movimientos.extemporaneos.devoluciones } //Dentro de este mismo bloque pueden ser llamadas así: do atipicos(d) do entradas(d) do extemporaneos.devoluciones(d) } ``` Si se invoca a una función dentro de un bloque cuyo espacio de nombres es el mismo que el de la función, no se requiere indicar el nombre completo. ``` program { module "Gestión de inventarios, movimientos:inventarios.movimientos" { //Dentro del bloque cuyo espacio de nombres es el mismo que el de la función, ambas sentencias son iguales do entradas(variable) do inventarios.movimientos.entradas(variable) } // Fuera del bloque es necesario usar el nombre completo do inventarios.movimientos.entradas(variable) } ``` ### Incorporación de espacios de nombres #### namespace La sentencia ```namespace "espacio.de.nombres"``` permite incluir en un bloque de código espacios de nombres predeterminados para que en caso de que alguna función no se encuentre por su nombre, se le adicionen como prefijos estos espacios de nombres indicados. ``` program "No hay ningún espacio de nombres indicado" { #include "inventarios.dkl" namespace "inventarios.movimientos" do entradas(variable) //Como no existe una función 'entradas' declarada en el bloque, se usará el espacio de nombres indicado para intentar encontrarla } ``` Si hay dos o más sentencias ```namespace``` en un bloque de código y hay más de una función cuyo nombre completo coincide con más de un espacio de nombres de los indicados, el intérprete de Devkron desencadenará una excepción de "Nombre de función ambigua", por lo que deberá indicar el nombre completo de la función o bien, usar un alias. ### Alias de funciones La sentencia ```alias "nombre.completo.funcion" "nombre_corto"``` permite establecer un nombre corto a una función que es válido dentro del bloque en donde se declare. ``` program ":mi.espacio.de.nombres" { nombre_de_funcion_largo_y_complicado::x,y { return x+y } codeblock { alias "mi.espacio.de.nombres.nombre_de_funcion_largo_y_complicado" "func" do func(4,5) //func es un nombre abreviado para la función nombre_de_funcion_largo_y_complicado } } ``` Los alias de funciones no son válidos en sentencias ```point to``` ni en bloques ```go```, en donde deberán usarse los nombres largos completos. ## Funciones definidas por el programador La declaración de funciones se realiza de la siguiente manera: ```DKL nombre_funcion :: arg1, arg2, ...argn { ... } ``` Ejemplos: ```DKL sumaAyB :: a, b { return a+b } funcion_sin_argumentos:: { } ``` Las funciones definidas por el programador tienen su propio ámbito cada una, por lo que las variables locales declaradas existen únicamente durante la ejecución de la función a la que pertenecen. Es posible declarar funciones dentro de funciones, pero se debe tener cuidado de hacerlo dentro de bloques ```module``` o ```codeblock``` para establecer explícitamente el espacio de nombres al que pertenecerán y evitar que con cada invocación de la función padre se creen valores duplicados en la tabla de funciones de la instancia en ejecución dependiendo del espacio de nombres en donde se realice dicha invocación. ``` funcion_padre:: { codeblock { hijo1:: { //Función declarada dentro de una función padre } hijo2:: { //Función declarada dentro de una función padre } } } ``` Todas las funciones devuelven un valor, si no se especifica con la sentencia return, la función devuelve cero. El número de parámetros definidos para la función es fijo. Los parámetros que deben ser tratados como tipos referencia, deben ser indicados con el carácter & precediendo al nombre: ```DKL funcion1:: parámetro_valor, &parametro_referencia { } ``` Las funciones deben ser declaradas antes del código que las llame, por lo que el siguiente código producirá un error de “función no encontrada”: ```DKL a=f1()+5 f1:: { return 3 } ``` El código debería ser como sigue: ```DKL f1:: { return 3 } a=f1()+5 ``` Sintaxis alternativa para declaración de funciones con la palabra reservada ```function``` ``` f1:: { return 3 } //Ambas declaraciones son iguales function f1() { return 3 } ```