├── .gitignore ├── birl ├── Cargo.toml ├── src │ ├── lib.rs │ ├── standard_lib │ │ ├── mod.rs │ │ └── text_manip.rs │ ├── modules.rs │ ├── context.rs │ ├── parser.rs │ ├── compiler.rs │ └── vm.rs └── DOC.md ├── shell ├── Cargo.toml ├── Cargo.lock └── src │ └── main.rs ├── exemplos ├── hello_world.birl ├── variaveis.birl ├── variaveis_padrao.birl ├── fatorial.birl ├── funções_e_condicionais.birl └── fibonacci.birl ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | */target 2 | .idea/ 3 | */.idea/ 4 | .c9/ 5 | */Cargo.lock 6 | *.swp 7 | */*.iml -------------------------------------------------------------------------------- /birl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "birl" 3 | version = "2.1.0" 4 | authors = ["Rafael Rodrigues Nakano "] 5 | 6 | -------------------------------------------------------------------------------- /birl/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod parser; 2 | pub mod context; 3 | pub mod vm; 4 | pub mod compiler; 5 | pub mod modules; 6 | pub mod standard_lib; 7 | -------------------------------------------------------------------------------- /shell/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "shell" 3 | version = "0.1.1" 4 | authors = ["Matheus Branco Borella ", "Rafael Rodrigues Nakano "] 5 | 6 | [dependencies] 7 | birl = { path = "../birl/" } 8 | -------------------------------------------------------------------------------- /shell/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "birl" 5 | version = "2.0.0" 6 | 7 | [[package]] 8 | name = "shell" 9 | version = "0.1.1" 10 | dependencies = [ 11 | "birl 2.0.0", 12 | ] 13 | 14 | -------------------------------------------------------------------------------- /exemplos/hello_world.birl: -------------------------------------------------------------------------------- 1 | # A JAULA SHOW é opcional, codigos podem ser executados fora de uma JAULA 2 | # porem uma jaula (no caso, a show) permite que se faça uso de recursão, o que não é disponivel em comandos globais 3 | CE QUER VER ISSO: "BORA, " + CUMPADE + "!" # O operador + em strings só pode ser usado com outra string 4 | -------------------------------------------------------------------------------- /exemplos/variaveis.birl: -------------------------------------------------------------------------------- 1 | JAULA SHOW 2 | VEM: MONSTRO, 0 # Declara variavel com o valor 0 3 | VEM: IBIRAPUERA, "BIRL" # Declara IBIRAPUERA com valor "BIRL" 4 | BORA: MONSTRO, 2 # Da o valor 2 para MONSTRO 5 | BORA: MONSTRO, MONSTRO * 2 # Multiplica o valor de MONSTRO por 2 6 | CE QUER VER ISSO: "MONSTRO: ", MONSTRO, " IBIRAPUERA: " + IBIRAPUERA 7 | SAINDO DA JAULA -------------------------------------------------------------------------------- /exemplos/variaveis_padrao.birl: -------------------------------------------------------------------------------- 1 | # Existem varias variaveis que são inicializadas por padrão, que são, por sua vez, constantes. 2 | # Elas são: 3 | CE QUER VER ISSO: CUMPADE # Contem seu nome de usuario 4 | CE QUER VER ISSO: UM # Teste, contem o valor 1 5 | CE QUER VER ISSO: BODYBUILDER # Outra constante, contem o valor BAMBAM 6 | 7 | JAULA SHOW() # Parenteses opcionais se nao houver parametros, tanto na declaração quanto na chamada 8 | CE QUER VER ISSO: JAULA # Contem o nome da JAULA atual, no caso, printa SHOW 9 | SAINDO DA JAULA -------------------------------------------------------------------------------- /exemplos/fatorial.birl: -------------------------------------------------------------------------------- 1 | JAULA FATORIAL (NUMERO: BATATA DOCE, ATUAL : BATATA DOCE) 2 | E ELE QUE A GENTE QUER: NUMERO, 1 3 | MENOR OU E MEMO: 4 | BIRL: ATUAL 5 | FIM 6 | BORA: NUMERO, NUMERO - 1 7 | BORA: ATUAL, ATUAL * NUMERO 8 | E HORA DO: FATORIAL, NUMERO, ATUAL 9 | BIRL: TREZE 10 | SAINDO DA JAULA 11 | 12 | JAULA SHOW 13 | VEM: NUMERO, 4 14 | CE QUER VER: "FATORIAL DE ", NUMERO, " É: " 15 | E HORA DO: FATORIAL, NUMERO, NUMERO 16 | CE QUER VER ISSO: TREZE 17 | SAINDO DA JAULA 18 | -------------------------------------------------------------------------------- /exemplos/funções_e_condicionais.birl: -------------------------------------------------------------------------------- 1 | JAULA OUTRO # Declaração da JAULA outro 2 | CE QUER VER ISSO: "estou em outra" 3 | SAINDO DA JAULA # Fim da declaração de OUTRO 4 | 5 | JAULA DIFERENTE() # No caso de nao possuir parametros, o uso de parenteses é opcional 6 | CE QUER VER ISSO: "deu diferente" 7 | SAINDO DA JAULA 8 | 9 | JAULA SHOW 10 | E HORA DO: OUTRO # Passa a execução pra OUTRO 11 | VEM: MUTANTE, "FIBRA" 12 | E ELE QUE A GENTE QUER: MUTANTE, "AGUA COM MUSCULO" # Compara MUTANTE com "AGUA COM MUSCULO" 13 | NUM E ELE: 14 | É HORA DO: DIFERENTE # Caso seja diferente, execute DIFERENTE 15 | FIM 16 | SAINDO DA JAULA 17 | -------------------------------------------------------------------------------- /exemplos/fibonacci.birl: -------------------------------------------------------------------------------- 1 | JAULA FIBONACCI(NUMERO: BATATA DOCE) 2 | E ELE QUE A GENTE QUER: NUMERO, 1 3 | MENOR OU E MEMO: 4 | BIRL: NUMERO 5 | FIM 6 | VEM: RESULTADO, 0 7 | E HORA DO: FIBONACCI, NUMERO - 1 8 | BORA: RESULTADO, TREZE 9 | E HORA DO: FIBONACCI, NUMERO - 2 10 | BIRL: RESULTADO + TREZE 11 | SAINDO DA JAULA 12 | 13 | JAULA PRINTA_FIBONACCI(TOTAL: BATATA DOCE, VEZES: BATATA DOCE) 14 | E ELE QUE A GENTE QUER: TOTAL, VEZES 15 | E ELE MEMO: 16 | BIRL 17 | FIM 18 | E HORA DO: FIBONACCI, TOTAL 19 | CE QUER VER ISSO: TREZE 20 | E HORA DO: PRINTA_FIBONACCI, TOTAL + 1, VEZES 21 | SAINDO DA JAULA 22 | 23 | JAULA SHOW 24 | VEM: VEZES, 13 25 | E HORA DO: PRINTA_FIBONACCI, 0, VEZES 26 | SAINDO DA JAULA 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 - 2019 Rafael Rodrigues Nakano 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /birl/src/standard_lib/mod.rs: -------------------------------------------------------------------------------- 1 | //! Base module for the standard library 2 | 3 | use std::env; 4 | 5 | use modules::*; 6 | use context::RawValue; 7 | 8 | mod text_manip; 9 | 10 | fn get_global_vars() -> Vec<(String, RawValue)> { 11 | vec! 12 | [ 13 | ("UM".to_owned(), RawValue::Integer(1)), 14 | ("CUMPADE".to_owned(), RawValue::Text(env::var("USER").unwrap_or("CUMPADE".to_owned()))), 15 | ("FRANGO".to_owned(), RawValue::Null), 16 | ] 17 | } 18 | 19 | pub fn module_standard_library() -> Module { 20 | let mut module = Module::new("PADRÃO".to_owned()); 21 | 22 | let modules_plugins = vec! 23 | [ 24 | text_manip::get_plugins() 25 | ]; 26 | 27 | let modules_vars = vec! 28 | [ 29 | get_global_vars() 30 | ]; 31 | 32 | let modules_source_functions : Vec> = vec! 33 | [ 34 | ]; 35 | 36 | for vars in modules_vars { 37 | for (name, value) in vars { 38 | module.global_variables.push(GlobalVariable::new(name, value, false)); 39 | } 40 | } 41 | 42 | for plugins in modules_plugins { 43 | for (name, params, func) in plugins { 44 | module.plugin_functions.push(Plugin::new(name, params, func)); 45 | } 46 | } 47 | 48 | for source_functions in modules_source_functions { 49 | for source_func in source_functions { 50 | module.source_functions.push(source_func); 51 | } 52 | } 53 | 54 | module 55 | } 56 | -------------------------------------------------------------------------------- /birl/src/modules.rs: -------------------------------------------------------------------------------- 1 | use context::RawValue; 2 | use vm::PluginFunction; 3 | use parser::{ Command, TypeKind, FunctionParameter }; 4 | 5 | pub struct GlobalVariable { 6 | pub name : String, 7 | pub writeable : bool, 8 | pub value : RawValue, 9 | } 10 | 11 | impl GlobalVariable { 12 | pub fn new(name : String, value : RawValue, writeable : bool) -> GlobalVariable { 13 | GlobalVariable { 14 | name, 15 | value, 16 | writeable 17 | } 18 | } 19 | } 20 | 21 | pub struct Plugin { 22 | pub name : String, 23 | pub parameters : Vec, 24 | pub func : PluginFunction, 25 | } 26 | 27 | impl Plugin { 28 | pub fn new(name : String, parameters : Vec, func : PluginFunction) -> Plugin { 29 | Plugin { 30 | name, 31 | parameters, 32 | func 33 | } 34 | } 35 | } 36 | 37 | pub struct SourceFunction { 38 | pub name : String, 39 | pub parameters : Vec, 40 | pub body : Vec, 41 | } 42 | 43 | impl SourceFunction { 44 | pub fn new(name : String, parameters : Vec, body : Vec) -> SourceFunction { 45 | SourceFunction { 46 | name, 47 | parameters, 48 | body 49 | } 50 | } 51 | } 52 | 53 | pub struct Module { 54 | pub global_variables : Vec, 55 | pub plugin_functions : Vec, 56 | pub source_functions : Vec, 57 | pub name : String, 58 | } 59 | 60 | impl Module { 61 | pub fn new(name : String) -> Module { 62 | Module { 63 | global_variables : vec![], 64 | plugin_functions : vec![], 65 | source_functions : vec![], 66 | name, 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BIRLSCRIPT 2 | 3 | É a linguagem de scripting dos programadores codebuilders! Dos que não saem de casa 4 | sem codar pra caralho! Se você ta achando que é moleza, ta enganado, aqui não é 5 | café com músculo, aqui se constrói código, porra! 6 | 7 | Se você é um programador mutante e se sente apto pro desafio, vá em frente! 8 | Ajude no desenvolvimento do projeto com ideias, código e muita fibra! 9 | 10 | Use o interpretador com a flag *-a* ou *--ajuda-o-maluco-ta-doente* para ver uma lista 11 | de opções que podem ser passadas. 12 | 13 | [Editor Online](https://birlscript.github.io/), pra rodar código na web 14 | 15 | ## Versão 2.1.0 16 | 17 | *© 2016-2019 Rafael Rodrigues Nakano. Contato: lazpeng@gmail.com* 18 | 19 | ### [Documentação disponível aqui](birl/DOC.md) 20 | 21 | # Exemplos 22 | 23 | ## Fatorial 24 | ``` 25 | JAULA FATORIAL (NUMERO: BATATA DOCE) 26 | É ELE QUE A GENTE QUER: NUMERO, 1 27 | MENOR OU É MEMO: 28 | BIRL: 1 29 | FIM 30 | VEM: TOTAL, NUMERO 31 | REPETE: ATUAL, NUMERO - 1, 1, (-1) 32 | BORA: TOTAL, TOTAL * ATUAL 33 | FIM 34 | BIRL: TOTAL 35 | SAINDO DA JAULA 36 | 37 | JAULA SHOW 38 | VEM: NUMERO, 4 39 | CE QUER VER: "FATORIAL DE ", NUMERO, " É: " 40 | E HORA DO: FATORIAL, NUMERO 41 | CE QUER VER ISSO: TREZE 42 | SAINDO DA JAULA 43 | ``` 44 | 45 | ## Sequência fibonacci 46 | ``` 47 | JAULA FIBONACCI(NUMERO: BATATA DOCE) 48 | E ELE QUE A GENTE QUER: NUMERO, 1 49 | MENOR OU E MEMO: 50 | BIRL: NUMERO 51 | FIM 52 | VEM: RESULTADO, 0 53 | E HORA DO: FIBONACCI, NUMERO - 1 54 | BORA: RESULTADO, TREZE 55 | E HORA DO: FIBONACCI, NUMERO - 2 56 | BIRL: RESULTADO + TREZE 57 | SAINDO DA JAULA 58 | 59 | JAULA PRINTA_FIBONACCI(TOTAL: BATATA DOCE, VEZES: BATATA DOCE) 60 | E ELE QUE A GENTE QUER: TOTAL, VEZES 61 | E ELE MEMO: 62 | BIRL 63 | FIM 64 | E HORA DO: FIBONACCI, TOTAL 65 | CE QUER VER ISSO: TREZE 66 | E HORA DO: PRINTA_FIBONACCI, TOTAL + 1, VEZES 67 | SAINDO DA JAULA 68 | 69 | JAULA SHOW 70 | VEM: VEZES, 13 71 | E HORA DO: PRINTA_FIBONACCI, 0, VEZES 72 | SAINDO DA JAULA 73 | 74 | ``` 75 | 76 | ## Hello world, cumpade! 77 | ``` 78 | # A JAULA SHOW é opcional, codigos podem ser executados fora de uma JAULA 79 | # porem uma jaula (no caso, a show) permite que se faça uso de recursão, o que não é disponivel em comandos globais 80 | CE QUER VER ISSO: "BORA, " + CUMPADE + "!" # O operador + em strings só pode ser usado com outra string 81 | ``` 82 | 83 | ## Funções e condicionais 84 | ``` 85 | JAULA OUTRO # Declaração da JAULA outro 86 | CE QUER VER ISSO: "estou em outra" 87 | SAINDO DA JAULA # Fim da declaração de OUTRO 88 | 89 | JAULA DIFERENTE() # No caso de nao possuir parametros, o uso de parenteses é opcional 90 | CE QUER VER ISSO: "deu diferente" 91 | SAINDO DA JAULA 92 | 93 | JAULA SHOW 94 | E HORA DO: OUTRO # Passa a execução pra OUTRO 95 | VEM: MUTANTE, "FIBRA" 96 | E ELE QUE A GENTE QUER: MUTANTE, "AGUA COM MUSCULO" # Compara MUTANTE com "AGUA COM MUSCULO" 97 | NUM E ELE: 98 | É HORA DO: DIFERENTE # Caso seja diferente, execute DIFERENTE 99 | FIM 100 | SAINDO DA JAULA 101 | ``` 102 | -------------------------------------------------------------------------------- /birl/src/standard_lib/text_manip.rs: -------------------------------------------------------------------------------- 1 | //! Module with text manipulation functions 2 | 3 | use parser::TypeKind; 4 | use vm::PluginFunction; 5 | 6 | mod plugins 7 | { 8 | use vm::{ DynamicValue, SpecialItemData, VirtualMachine }; 9 | use parser::IntegerType; 10 | 11 | /// Split an string into multiple parts based on another string 12 | /// Arguments : source : Text, splitter : Text2 13 | pub fn split_string(mut arguments : Vec, vm : &mut VirtualMachine) -> Result, String> { 14 | // Well since it seems Birlscript passes arguments in the reverse order 15 | 16 | let result = { 17 | let mut get_str_arg = || 18 | { 19 | match arguments.remove(0) { 20 | DynamicValue::Text(id) => { 21 | match vm.get_special_storage_ref().get_data_ref(id) 22 | { 23 | Some(data) => match data { 24 | SpecialItemData::List(_) => unreachable!(), 25 | SpecialItemData::Text(s) => Ok(s), 26 | } 27 | None => Err("Erro interno : Dado special com ID fornecido não existe".to_owned()) 28 | } 29 | } 30 | _ => unreachable!() 31 | } 32 | }; 33 | 34 | let splitter = get_str_arg()?; 35 | 36 | let source = get_str_arg()?; 37 | 38 | source.split(splitter).map(|e| e.to_owned()).collect::>() 39 | }; 40 | 41 | let result_id = { 42 | let storage = vm.get_special_storage_mut(); 43 | 44 | let elements = result.into_iter().map(|e| Box::new(DynamicValue::Text(storage.add(SpecialItemData::Text(e), 0u64)))).collect::>>(); 45 | 46 | storage.add(SpecialItemData::List(elements), 0u64) 47 | }; 48 | 49 | Ok(Some(DynamicValue::List(result_id))) 50 | } 51 | 52 | /// Returns the length of the given string 53 | /// Arguments : String 54 | pub fn get_string_length(mut arguments : Vec, vm : &mut VirtualMachine) -> Result, String> { 55 | let length = { 56 | match arguments.remove(0) { 57 | DynamicValue::Text(id) => { 58 | match vm.get_special_storage_ref().get_data_ref(id) { 59 | Some(data) => match data { 60 | &SpecialItemData::Text(ref t) => t.len(), 61 | _ => return Err("".to_owned()) 62 | } 63 | None => return Err("ID special inválida".to_owned()) 64 | } 65 | } 66 | _ => unreachable!() 67 | } 68 | }; 69 | 70 | Ok(Some(DynamicValue::Integer(length as IntegerType))) 71 | } 72 | } 73 | 74 | pub fn get_plugins() -> Vec<(String, Vec, PluginFunction)> 75 | { 76 | vec! 77 | [ 78 | ("DIVIDE TEXTO".to_owned(), vec![TypeKind::Text, TypeKind::Text], plugins::split_string), 79 | ("TAMANHO DO TEXTO".to_owned(), vec![TypeKind::Text], plugins::get_string_length), 80 | ] 81 | } -------------------------------------------------------------------------------- /shell/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate birl; 2 | 3 | use std::env::args; 4 | use std::process::exit; 5 | use birl::context::Context; 6 | use birl::compiler::CompilerHint; 7 | use birl::context::BIRL_GLOBAL_FUNCTION_ID; 8 | 9 | pub const SHELL_COPYRIGHT : &'static str 10 | = "© 2019 Rafael Rodrigues Nakano, Matheus Branco Borella"; 11 | 12 | fn start_interactive_console(c: &mut Context) { 13 | /* Print heading info. */ 14 | eprintln!("Birlscript versão {}", birl::context::BIRL_VERSION); 15 | eprintln!("{}", birl::context::BIRL_COPYRIGHT); 16 | eprintln!("{}", SHELL_COPYRIGHT); 17 | eprintln!(); 18 | 19 | c.set_interactive_mode(); 20 | 21 | /* Bind the Context interpreter to standard IO */ 22 | let _ = c.set_stdin({ 23 | use std::io; 24 | let reader = io::BufReader::new(io::stdin()); 25 | Some(Box::new(reader)) 26 | }); 27 | let _ = c.set_stdout({ 28 | use std::io; 29 | Some(Box::new(io::stdout())) 30 | }); 31 | 32 | /* Enter interactive loop */ 33 | use std::io::{stdin, BufReader, BufRead}; 34 | let mut prompt = BufReader::new(stdin()); 35 | let mut scope_level = 0usize; 36 | loop{ 37 | if scope_level == 0 { 38 | eprint!("> "); 39 | } else { 40 | eprint!(">>"); 41 | 42 | for _ in 0..scope_level { 43 | eprint!("\t"); 44 | } 45 | } 46 | 47 | let mut line = String::new(); 48 | match prompt.read_line(&mut line){ 49 | Ok(count) => if count == 0 { 50 | eprintln!("Reached end of input."); 51 | break 52 | }, 53 | Err(what) => { 54 | eprintln!("A read error occured: {:?}", what); 55 | break 56 | } 57 | } 58 | 59 | match c.process_line(&line) { 60 | Ok(None) => {} 61 | Ok(Some(hint)) => { 62 | match hint { 63 | CompilerHint::ScopeStart => scope_level += 1, 64 | CompilerHint::ScopeEnd => scope_level -= 1, 65 | } 66 | } 67 | Err(e) => eprintln!("{}", e) 68 | }; 69 | 70 | if scope_level == 0 { 71 | match c.interactive_prepare_resume() { 72 | Ok(_) => {} 73 | Err(e) => eprintln!("{}", e) 74 | } 75 | 76 | use birl::vm::ExecutionStatus as Es; 77 | loop { 78 | match c.execute_next_instruction() { 79 | Ok(Es::Quit) => { 80 | eprintln!("Saindo..."); 81 | return; 82 | } 83 | Ok(Es::Halt) => break, 84 | Ok(_) => {} 85 | Err(e) => { 86 | eprintln!("{}", e); 87 | } 88 | } 89 | } 90 | } 91 | } 92 | 93 | /* Make sure the output is flushed */ 94 | c.set_stdout(None).unwrap().flush() 95 | .expect("Could not flush io::stdout()."); 96 | } 97 | 98 | fn print_help() { 99 | Context::print_version(); 100 | 101 | println!("Ta querendo ajuda, cumpade?"); 102 | println!("O uso é o seguinte: birl [opções] [arquivo ou arquivos]"); 103 | println!("Cê pode passar mais de um arquivo, só que apenas um pode ter a seção \"SHOW\", que \ 104 | é o ponto de partida do teu programa."); 105 | println!("As opções são as seguintes:"); 106 | println!("\t-a ou --ajuda-o-maluco-ta-doente\t: Imprime essa mensagem de ajuda"); 107 | println!("\t-v ou --versao\t\t\t\t: Imprime a versão do programa"); 108 | println!("\t-s ou --string \"[codigo]\"\t\t: Executa o codigo na string ao inves de \ 109 | um arquivo."); 110 | println!("\t-i ou --interativo\t\t\t\t: Inicia um console interativo pra rodar códigos"); 111 | println!("\t-p ou --sem-padrão\t\t\t\t: Não adiciona as definições da biblioteca padrão"); 112 | } 113 | 114 | /// Parameters passed through the command line 115 | enum Param { 116 | PrintVersion, 117 | PrintHelp, 118 | /// Add a file to be processed 119 | InputFile(String), 120 | /// Processes code from a given string 121 | StringSource(String), 122 | /// Starts an interactive console for running code 123 | Interactive, 124 | /// Do not add the standard library to the code 125 | WithoutStdLib, 126 | } 127 | 128 | fn get_params() -> Vec { 129 | let mut arguments = args(); 130 | let mut result: Vec = vec![]; 131 | 132 | let _ = arguments.next().unwrap(); // Dispose of the first argument 133 | 134 | loop { 135 | if let Some(arg) = arguments.next() { 136 | match arg.as_str() { 137 | "-a" | "--ajuda-o-maluco-ta-doente" => result.push(Param::PrintHelp), 138 | "-v" | "--versao-cumpade" => result.push(Param::PrintVersion), 139 | "-i" | "--interativo" => result.push(Param::Interactive), 140 | "-s" | "--string" => { 141 | // The next argument is expected to be a string containing source code 142 | if let Some(code) = arguments.next() { 143 | result.push(Param::StringSource(code)); 144 | } else { 145 | println!("Erro: O argumento {} precisa de um conteúdo logo em seguida, bixo.", arg); 146 | } 147 | } 148 | "-p" | "--sem-padrao" | "--sem-padrão" => result.push(Param::WithoutStdLib), 149 | // Push the file to the result stack 150 | _ => result.push(Param::InputFile(arg)) 151 | } 152 | } else { 153 | break; 154 | } 155 | } 156 | 157 | result 158 | } 159 | 160 | fn main() { 161 | let args = get_params(); 162 | let mut interactive = false; 163 | let mut with_stdlib = true; 164 | let mut files = vec![]; 165 | let mut strings = vec![]; 166 | 167 | let mut ctx = Context::new(); 168 | 169 | match ctx.call_function_by_id(BIRL_GLOBAL_FUNCTION_ID, vec![]) { 170 | Ok(_) => {} 171 | Err(e) => { 172 | println!("Erro iniciando o contexto : {}", e); 173 | 174 | exit(-1); 175 | } 176 | } 177 | 178 | if args.len() > 0 { 179 | for arg in args { 180 | match arg { 181 | Param::PrintHelp => print_help(), 182 | Param::Interactive => interactive = true, 183 | Param::PrintVersion => Context::print_version(), 184 | Param::WithoutStdLib => with_stdlib = false, 185 | Param::InputFile(file) => files.push(file), 186 | Param::StringSource(source) => strings.push(source), 187 | } 188 | } 189 | } else { 190 | interactive = true; 191 | } 192 | 193 | if with_stdlib { 194 | match ctx.add_standard_library() { 195 | Ok(_) => {} 196 | Err(e) => { 197 | println!("Erro adicionando standard library : {}", e); 198 | exit(-1); 199 | } 200 | } 201 | } 202 | 203 | for file in files { 204 | match ctx.add_file(file.as_str()) { 205 | Ok(_) => {} 206 | Err(e) => { 207 | println!("Ocorreu um erro ao adicionar o arquivo \"{}\" pro contexto : {}", 208 | file.as_str(), e); 209 | exit(-1); 210 | } 211 | } 212 | } 213 | 214 | for source in strings { 215 | match ctx.add_source_string(source) { 216 | Ok(_) => {} 217 | Err(e) => { 218 | println!("Erro ao adicionar string de código ao contexto : {}", e); 219 | } 220 | } 221 | } 222 | 223 | if interactive { 224 | start_interactive_console(&mut ctx); 225 | } else { 226 | /* Bind the Context interpreter to standard IO */ 227 | let _ = ctx.set_stdin({ 228 | use std::io; 229 | let reader = io::BufReader::new(io::stdin()); 230 | Some(Box::new(reader)) 231 | }); 232 | let _ = ctx.set_stdout({ 233 | use std::io; 234 | Some(Box::new(io::stdout())) 235 | }); 236 | 237 | match ctx.start_program() { 238 | Ok(_) => {} 239 | Err(e) => println!("Erro de execução : {}", e), 240 | } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /birl/src/context.rs: -------------------------------------------------------------------------------- 1 | //! Hosts the runtime for the birlscript language 2 | 3 | use vm::{VirtualMachine, ExecutionStatus, PluginFunction, Instruction}; 4 | use parser::{ parse_line, TypeKind, ParserResult, IntegerType, FunctionDeclaration }; 5 | use compiler::{ Compiler, CompilerHint }; 6 | use modules::*; 7 | use standard_lib::module_standard_library; 8 | 9 | use std::io::{ BufRead, BufReader, Write }; 10 | use std::fs::File; 11 | 12 | pub const BIRL_COPYRIGHT : &'static str 13 | = "© 2016 - 2019 Rafael Rodrigues Nakano"; 14 | pub const BIRL_VERSION : &'static str 15 | = "BirlScript v2.1.0"; 16 | pub const BIRL_MAIN_FUNCTION : &str 17 | = "SHOW"; 18 | 19 | pub const BIRL_MAIN_FUNCTION_ID : usize = 1; 20 | pub const BIRL_GLOBAL_FUNCTION_ID : usize = 0; 21 | pub const BIRL_RET_VAL_VAR_ADDRESS : usize = 0; 22 | 23 | #[derive(Debug, Clone, PartialEq)] 24 | pub enum RawValue { 25 | Text(String), 26 | Integer(IntegerType), 27 | Number(f64), 28 | Null, 29 | } 30 | 31 | impl RawValue { 32 | pub fn get_kind(&self) -> TypeKind { 33 | match &self { 34 | &RawValue::Integer(_) => TypeKind::Integer, 35 | &RawValue::Number(_) => TypeKind::Number, 36 | &RawValue::Text(_) => TypeKind::Text, 37 | &RawValue::Null => TypeKind::Null, 38 | } 39 | } 40 | } 41 | 42 | pub struct Context { 43 | vm : VirtualMachine, 44 | has_main : bool, 45 | compiler : Compiler, 46 | current_code_id : usize, 47 | } 48 | 49 | impl Context { 50 | /// Alias for vm.set_stdout(). 51 | pub fn set_stdout(&mut self, write: Option>) -> Option>{ 52 | self.vm.set_stdout(write) 53 | } 54 | 55 | /// Alias for vm.set_stdin(). 56 | pub fn set_stdin(&mut self, read: Option>) -> Option>{ 57 | self.vm.set_stdin(read) 58 | } 59 | 60 | pub fn new() -> Context { 61 | let mut vm = VirtualMachine::new(); 62 | let _ = vm.add_new_code(); // For global 63 | let _ = vm.add_new_code(); // For main 64 | 65 | Context { 66 | vm, 67 | has_main : false, 68 | compiler : Compiler::new(), 69 | current_code_id : 0, 70 | } 71 | } 72 | 73 | fn add_function(&mut self, f : FunctionDeclaration) -> Result<(), String> { 74 | let is_main = f.name == BIRL_MAIN_FUNCTION; 75 | if is_main { 76 | if self.has_main { 77 | return Err("Erro: Múltipla declaração da função principal".to_owned()); 78 | } 79 | if f.arguments.len() != 0 { 80 | return Err("Erro : Declaração da função principal inválida : A função principal não deve pedir argumentos".to_owned()); 81 | } 82 | self.has_main = true; 83 | } 84 | 85 | let id = if is_main { 86 | BIRL_MAIN_FUNCTION_ID 87 | } else { 88 | self.vm.add_new_code() 89 | }; 90 | 91 | self.compiler.begin_compiling_function(id, f.arguments, f.name)?; 92 | 93 | self.current_code_id = id; 94 | 95 | Ok(()) 96 | } 97 | 98 | pub fn set_interactive_mode(&mut self) { 99 | self.vm.set_interactive_mode(); 100 | } 101 | 102 | pub fn end_function(&mut self) -> Result<(), String>{ 103 | match self.vm.get_code_for(self.current_code_id) { 104 | Some(f) => self.compiler.end_compiling_function(f)?, 105 | None => return Err("Nenhuma função em compilação".to_owned()) 106 | }; 107 | 108 | self.current_code_id = BIRL_GLOBAL_FUNCTION_ID; 109 | 110 | Ok(()) 111 | } 112 | 113 | pub fn process_line(&mut self, line : &str) -> Result, String> { 114 | 115 | let result = match parse_line(line) { 116 | Ok(r) => r, 117 | Err(e) => return Err(e) 118 | }; 119 | 120 | match result { 121 | ParserResult::Command(cmd) => { 122 | let hint = { 123 | let instructions = match self.vm.get_code_for(self.current_code_id) { 124 | Some(i) => i, 125 | None => return Err(format!("Erro ao pegar o código para a função atual")) 126 | }; 127 | 128 | match self.compiler.compile_command(cmd, instructions) { 129 | Ok(hint) => hint, 130 | Err(e) => return Err(e) 131 | } 132 | }; 133 | 134 | Ok(hint) 135 | } 136 | ParserResult::FunctionEnd => { 137 | self.end_function()?; 138 | 139 | Ok(Some(CompilerHint::ScopeEnd)) 140 | }, 141 | ParserResult::FunctionStart(func) => { 142 | self.add_function(func)?; 143 | 144 | Ok(Some(CompilerHint::ScopeStart)) 145 | }, 146 | ParserResult::Nothing => Ok(None) 147 | } 148 | } 149 | 150 | pub fn add_source_string(&mut self, string : String) -> Result<(), String> { 151 | let reader = BufReader::new(string.as_bytes()); 152 | 153 | for line in reader.lines() { 154 | match line { 155 | Ok(line) => { 156 | match self.process_line(line.as_str()) { 157 | Ok(_) => {} 158 | Err(e) => return Err(e) 159 | } 160 | } 161 | Err(e) => return Err(format!("{:?}", e)) 162 | } 163 | } 164 | 165 | Ok(()) 166 | } 167 | 168 | pub fn add_file(&mut self, filename : &str) -> Result<(), String> { 169 | let file = match File::open(filename) { 170 | Ok(f) => f, 171 | Err(e) => return Err(format!("{:?}", e)), 172 | }; 173 | 174 | let mut line_num = 0usize; 175 | 176 | let reader = BufReader::new(file); 177 | 178 | for line in reader.lines() { 179 | line_num += 1; 180 | match line { 181 | Ok(line) => { 182 | match self.process_line(line.as_str()) { 183 | Ok(_) => {} 184 | Err(e) => return Err(format!("(Linha {}) : {:?}", line_num, e)) 185 | } 186 | } 187 | Err(e) => return Err(format!("(Linha {}) : {:?}", line_num, e)) 188 | } 189 | } 190 | 191 | Ok(()) 192 | } 193 | 194 | pub fn add_plugin(&mut self, name : String, parameters : Vec, code : PluginFunction) -> Result<(), String> { 195 | let index = self.vm.add_new_plugin(code); 196 | 197 | self.compiler.add_plugin_function_definition(index, parameters, name)?; 198 | 199 | Ok(()) 200 | } 201 | 202 | pub fn add_global_variable(&mut self, name : String, value : RawValue, writeable : bool) -> Result<(), String> { 203 | let mut inst = vec![]; 204 | 205 | self.compiler.compile_global_variable(name, value, writeable, &mut inst)?; 206 | 207 | for i in inst { 208 | match self.vm.run(i)? { 209 | ExecutionStatus::Halt => break, 210 | ExecutionStatus::Quit => return Err("VM Quitou enquanto adicionava var".to_owned()), 211 | ExecutionStatus::Normal => {} 212 | ExecutionStatus::Returned => return Err("VM Retornou enquanto adicionava var".to_owned()) 213 | } 214 | } 215 | 216 | Ok(()) 217 | } 218 | 219 | pub fn add_module(&mut self, module : Module) -> Result<(), String> { 220 | 221 | for var in module.global_variables { 222 | self.add_global_variable(var.name, var.value, var.writeable)?; 223 | } 224 | 225 | for src in module.source_functions { 226 | let mut decl = FunctionDeclaration::from(src.name); 227 | decl.arguments = src.parameters; 228 | 229 | self.add_function(decl)?; 230 | 231 | for c in src.body { 232 | let instructions = match self.vm.get_code_for(self.current_code_id) { 233 | Some(i) => i, 234 | None => return Err(format!("Erro ao pegar o código para a função atual")) 235 | }; 236 | 237 | match self.compiler.compile_command(c, instructions) { 238 | Ok(_) => {}, 239 | Err(e) => return Err(e) 240 | } 241 | } 242 | 243 | self.end_function()?; 244 | } 245 | 246 | for plg in module.plugin_functions { 247 | self.add_plugin(plg.name, plg.parameters, plg.func)?; 248 | } 249 | 250 | Ok(()) 251 | } 252 | 253 | /// Prepares the context to begin executing interactive code again after an Halt 254 | pub fn interactive_prepare_resume(&mut self) -> Result<(), String> 255 | { 256 | // all this does is put an Halt in the end of the global function, so the program stops on its own 257 | 258 | match self.vm.get_code_for(BIRL_GLOBAL_FUNCTION_ID) { 259 | Some(c) => c.push(Instruction::Halt), 260 | None => return Err("Contexto não foi iniciado corretamente".to_owned()) 261 | } 262 | 263 | Ok(()) 264 | } 265 | 266 | pub fn add_standard_library(&mut self) -> Result<(), String> { 267 | let m = module_standard_library(); 268 | 269 | self.add_module(m) 270 | } 271 | 272 | pub fn call_function_by_id(&mut self, id : usize, args : Vec) -> Result<(), String> { 273 | let mut instructions = vec![]; 274 | 275 | match self.compiler.compile_function_call(id, args, &mut instructions) { 276 | Ok(_) => {} 277 | Err(e) => return Err(e), 278 | } 279 | 280 | for i in instructions { 281 | match self.vm.run(i) { 282 | Ok(_) => {} 283 | Err(e) => return Err(e) 284 | } 285 | } 286 | 287 | Ok(()) 288 | } 289 | 290 | pub fn execute_next_instruction(&mut self) -> Result { 291 | self.vm.execute_next_instruction() 292 | } 293 | 294 | pub fn start_program(&mut self) -> Result<(), String> { 295 | // Global function is already running 296 | 297 | loop { 298 | match self.execute_next_instruction() { 299 | Ok(ExecutionStatus::Normal) => {} 300 | Ok(ExecutionStatus::Returned) => {} 301 | Ok(ExecutionStatus::Halt) => break, 302 | Ok(ExecutionStatus::Quit) => break, 303 | Err(e) => return Err(e) 304 | } 305 | } 306 | 307 | self.vm.unset_quit(); 308 | 309 | if self.has_main { 310 | match self.call_function_by_id(BIRL_MAIN_FUNCTION_ID, vec![]) { 311 | Ok(_) => {} 312 | Err(e) => return Err(e) 313 | } 314 | 315 | loop { 316 | match self.execute_next_instruction() { 317 | Ok(ExecutionStatus::Normal) => {} 318 | Ok(ExecutionStatus::Returned) => {} 319 | Ok(ExecutionStatus::Halt) => break, 320 | Ok(ExecutionStatus::Quit) => return Ok(()), 321 | Err(e) => return Err(e) 322 | } 323 | } 324 | } 325 | 326 | Ok(()) 327 | } 328 | 329 | pub fn print_version() { 330 | println!("{}", BIRL_VERSION); 331 | println!("{}", BIRL_COPYRIGHT); 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /birl/DOC.md: -------------------------------------------------------------------------------- 1 | # Documentação 2 | **BirlScript 2.0.0** 3 | **Rafael Rodrigues Nakano ** 4 | 5 | BirlScript é uma linguagem de tipagem dinâmica e interpretada 6 | (por enquanto não existe uma ABI/bytecode formada e eu não acho que 7 | vale o esforço pra compilar isso), que nasceu de uma piada em 2016. 8 | Na época eu usei o projeto pra aprender mais sobre Rust, e por isso a 9 | versão 1.0 era horrível. Embora tenha sido um grande aprendizado, 10 | não só em relação a Rust mas também em design e implementação de 11 | linguagens de programação (se bem que a única coisa de design que 12 | eu aprendi foi como *não* fazer as coisas), e por isso eu sempre tive 13 | em mente uma versão 2.0, onde eu pudesse empregar tudo o que eu aprendi 14 | enquanto fazendo o original (que eu não implementei por ser muito diferente 15 | da base que já existia, ou seja, precisava ser do zero) e estudando 16 | material já existente pra incorporar algorítimos e ideias da indústria 17 | à respeito de linguagens de programação. Só que essa última parte eu não fiz. 18 | 19 | Por mais que eu não tenha estudado muito a fundo, eu aprendi algumas coisas meio 20 | que indiretamente, e apliquei onde eu pude. O maior problema é que o design antigo 21 | era extremamente ruim, e *cortava caminho* onde podia. Eu não consigo imaginar 22 | BirlScript sendo um C só que com *keywords* engraçadas, e o coração da lang 23 | tava no design antigo, por mais que fosse ruim. 24 | 25 | Então, é, abaixo tem um resumo e descrição de comandos e o comportamento 26 | em geral. Contribuições são bem-vindas, principalmente em relação à linguagem em si, 27 | como nomes de comandos e etc. Entrar em contato comigo ou fazer uma pull request 28 | são opções, e não esqueça de testar tudo e alterar essa documentação pra refletir 29 | o novo comportamento se for necessário. 30 | 31 | # Especificação da linguagem 32 | BirlScript é uma linguagem dinâmica e interpretada. O objetivo inicial 33 | era ter algo parecido com BASIC ou até assembly, mas acabou """evoluindo""" pra algo ~~pior~~ diferente. 34 | 35 | Basicamente tudo em BirlScript é feito por meio de comandos, e até a declaração 36 | de funções é, internamente, tratada como um comando. Comandos podem existir dentro de funções ou no contexto "global", que é uma função executada antes da principal e não pode ser chamada pelo código. A função principal é chamada de SHOW e é chamada depois da execução da função global, e pode ser chamada por outras funções ou até por ela mesma (se por algum motivo for necessário). A sintaxe pra declaração de uma função é a seguinte: 37 | ``` 38 | JAULA nome da função (argumentos...) 39 | ``` 40 | Nomes em BirlScript podem possuir espaços, desde que o primeiro caractere de cada palavra seja um alpha válido (e.g. "TESTE 2" não é válido, 2 é o primeiro caractere da palavra e é interpretado como o número 2) e para no fim do *input*, um *tab*, nova linha ou dois espaços seguidos são encontrados. 41 | A função aceita uma lista de argumentos delimitada por parênteses, separados por vírgula e seguindo a sintaxe abaixo: 42 | ``` 43 | nome do argumento : tipo 44 | ``` 45 | Para encerrar o corpo da função, `SAINDO DA JAULA` é usado. Tudo entre o início e esse comando é considerado parte da função. 46 | 47 | ## Comandos 48 | Os comandos são as formas de executar ações no código BirlScript, como dar um valor a uma variável, declarar uma variável, executar uma função e etc. 49 | A sintaxe pra execução de um comando é : 50 | ``` 51 | nome do comando : argumentos... 52 | ``` 53 | Alguns comandos que não recebem nenhum argumento ou em que os únicos argumentos são opcionais podem omitir o `:` 54 | 55 | A forma como os argumentos são passados depende de comando pra comando. Alguns pedem o nome de uma variável no lugar de um argumento específico para, por exemplo, ler o valor dessa variável. Em outros casos, é pedida uma *expressão*, que é simplesmente algo que gere um valor, como por exemplo `2+2`, `"olá"` ou `variável + "!"`. 56 | 57 | Abaixo há a lista de todos os comandos presentes na linguagem BirlScript e os argumentos que cada um requer. 58 | ### BIRL (Return) 59 | Retorna pra função anterior. Um valor é opcional 60 | 61 | Argumentos : 62 | * (opcional) Valor : O valor pra ser retornado pra função anterior. Se nada for passado, é Null 63 | ### NUM VAI DÁ NÃO (Quit) 64 | Encerra e execução do programa 65 | ### CE QUER VER (Print) 66 | *Printa* zero ou mais valores pra saída padrão, e só. 67 | 68 | Argumentos : 69 | * (opcional) Valor : O que é *printado*. 70 | * ... Valores 71 | ### CE QUER VER ISSO (PrintLn) 72 | *Printa* zero ou mais valores pra saída padrão, seguido de uma nova linha 73 | 74 | Argumentos : 75 | * (opcional) Valor : mesma coisa 76 | ### *sem nome* (PrintDebug) 77 | Esse comando só existe pro console interativo, embora *seja* possível "usá-lo" 78 | normalmente, só não faz nada. O que isso faz é basicamente o mesmo que os dois 79 | acima, mas com informação adicional sobre o tipo do valor, e aceita somente um argumento 80 | 81 | Argumentos : 82 | * Valor : O valor 83 | ### VEM (Declare) 84 | Declara uma variável com um valor inicial, ou, se nada for passado, Null. 85 | Se a variável já existir em um escopo acima, essa é usada até o fim do escopo. 86 | A variável pode ser modificada por outros comandos, ou seja, não é constante. 87 | 88 | Argumentos : 89 | * Nome : Nome dado pra variável 90 | * (opcional) Valor : valor inicial 91 | ### BORA (Set) 92 | Muda o valor de uma variável, que já foi declarada anteriormente. 93 | 94 | Argumentos : 95 | * Nome : nome da variável 96 | * Valor : novo valor 97 | ### É ELE QUE A GENTE QUER (Compare) 98 | Compara dois valores dados como argumentos. Se um dos valores for Null, o 99 | resultado é sempre diferente. Se os dois forem Null, é igual 100 | 101 | Argumentos : 102 | * Valor 1 103 | * Valor 2 104 | ### FIM (EndSubScope) 105 | Encerra um bloco (condicional ou loop) 106 | ### É ELE MEMO (ExecuteIfEqual) 107 | Executa o bloco de comandos se a última comparação foi Igual 108 | ### NUM É ELE (ExecuteIfNotEqual) 109 | Executa o bloco de comandos se a última comparação não foi Igual 110 | ### MENOR OU É MEMO (ExecuteIfEqualOrLess) 111 | Executa o bloco de comandos se a última comparação foi Igual ou Menor 112 | ### É MENOR (ExecuteIfLess) 113 | Executa o bloco de comandos se a última comparação foi Menor 114 | ### MAIOR OU É MEMO (ExecuteIfEqualOrGreater) 115 | Executa o bloco de comandos se a última comparação foi Igual ou Maior 116 | ### É MAIOR (ExecuteIfGreater) 117 | Executa o bloco de comandos se a última comparação foi Maior 118 | ### É HORA DO (Call) 119 | Executa uma função com os argumentos passados. O valor de retorno da função 120 | fica na variável TREZE 121 | 122 | Argumentos : 123 | * Função 124 | * (opcional) Argumentos ... : Caso tenha 125 | ### FALA AÍ (GetStringInput) 126 | Pede um Texto como *input* da entrada padrão. 127 | 128 | Argumentos : 129 | * Variável : variável que recebe o valor recebido 130 | ### FALA UM NÚMERO (GetNumberInput) 131 | Pede um Número como *input* da entrada padrão. 132 | 133 | Argumentos : 134 | * Variável : variável que recebe o valor recebido 135 | ### FALA UM INTEIRO (GetIntegerInput) 136 | Pede um Inteiro como *input* da entrada padrão. 137 | 138 | Argumentos : 139 | * Variável : variável que recebe o valor recebido 140 | ### MUDA PRA NÚMERO (ConvertToNum) 141 | Converte o valor de uma variável pra Número. O valor original é perdido 142 | e a variável recebe o novo valor. 143 | 144 | Argumentos : 145 | * Valor : O valor pra ser convertido 146 | ### MUDA PRA INTEIRO (ConvertToInt) 147 | Converte o valor de uma variável pra Inteiro. O valor original é perdido 148 | e a variável recebe o novo valor. 149 | 150 | Argumentos : 151 | * Valor : O valor pra ser convertido 152 | ### MUDA PRA TEXTO (IntoString) 153 | Converte o valor de uma variável pra Texto. O valor original é perdido 154 | e a variável recebe o novo valor. 155 | 156 | Argumentos : 157 | * Valor : O valor pra ser convertido 158 | ### ENQUANTO É ELE MEMO (ExecuteWhileEqual) 159 | Executa o bloco de comandos enquanto a última comparação for Igual 160 | ### ENQUANTO NUM É ELE (ExecuteWhileNotEqual) 161 | Executa o bloco de comandos enquanto a última comparação não for Igual 162 | ### ENQUANTO MENOR OU É MEMO (ExecuteWhileEqualOrLess) 163 | Executa o bloco de comandos enquanto a última comparação for Igual ou Menor 164 | ### ENQUANTO É MENOR (ExecuteWhileLess) 165 | Executa o bloco de comandos enquanto a última comparação for Menor 166 | ### ENQUANTO MAIOR OU É MEMO (ExecuteWhileEqualOrGreater) 167 | Executa o bloco de comandos enquanto a última comparação for Igual ou Maior 168 | ### ENQUANTO É MAIOR (ExecuteWhileGreater) 169 | Executa o bloco de comandos enquanto a última comparação for Maior 170 | ### REPETE (RangeLoop) 171 | Repete um bloco de comandos por um número de vezes. 172 | 173 | Argumentos: 174 | * Variável : Nome da variável pra receber o valor do index pra cada iteração. 175 | Se não existir, é declarada pelo comando. 176 | * Valor de início : Expressão que resulta em um número inteiro que é o primeiro index 177 | * Valor final : Expressão que resulta em um inteiro que é o último index - 1 (isso é, o index nunca chega no valor final). Se o valor final for menor que o inicial (o loop é reverso), *stepping* deve ser usado com um valor negativo 178 | * (opcional) *stepping* : Expressão que resulta em um inteiro que é usado como modificador pro index a cada iteração. (Padrão : 1) 179 | ### PARA AQUI (BreakScope) 180 | Encerra a execução de algum bloco condicional. No caso de um loop, a condição pra 181 | continuar é ignorada, então esse comando não deve ser confundido com um *continue* em 182 | linguagens como C ou C++, por exemplo. 183 | ### VAI PRO PRÓXIMO (SkipNextIteration) 184 | Mesma coisa do BreakScope, mas continua a próxima iteração, incluindo a parte de incrementar o index. Mesma funcionalidade 185 | de um *continue* em outras linguagens. 186 | Esse, porém, não funciona em condicionais, só em loops. Usar esse comando fora de algum loop resulta em um erro na execução. 187 | ### FAZ UMA LISTA (MakeNewList) 188 | Cria uma nova lista vazia. Se a variável passada como argumento já existir, o valor nela é perdido 189 | e substituído pela lista. Se não, ela é criada 190 | 191 | Argumentos : 192 | * Nome : nome pra lista 193 | ### FALA O TAMANHO (QueryListSize) 194 | Busca pelo tamanho de uma lista, e coloca esse valor na segunda variável passada como argumento 195 | 196 | Argumentos : 197 | * Lista : Nome da variável carregando a lista 198 | * Tamanho : Nome da variável pra receber o tamanho 199 | ### PÕE ISSO AQUI (AddListElement) 200 | Adiciona um elemento em uma lista. Opcionalmente, você pode escolher em que posição colocar o elemento. 201 | Se a posição especificada for depois do fim da lista, o elemento é colocado no final 202 | 203 | Argumentos : 204 | * Lista : Nome da lista 205 | * Variável : Elemento pra ser adicionado 206 | * (opcional) Índice : Aonde colocar o elemento 207 | ### TIRA ESSE (RemoveListElement) 208 | Remove um elemento do índice passado. Se o índice for inválido, um erro acontece. 209 | 210 | Argumentos : 211 | * Lista 212 | * Índice do elemento 213 | ### ME DÁ ESSE (IndexList) 214 | Indexa um elemento da lista passada e coloca o valor dele na variável passada 215 | 216 | Argumentos : 217 | * Lista 218 | * Índice : De onde tirar o elemento 219 | * Elemento : Variável pra receber o valor do elemento 220 | ## Variáveis padrão 221 | São variáveis disponíveis no escopo global e não podem ser modificadas. O principal motivo de existirem é pra testes e zoeira. 222 | 223 | * CUMPADE : Tem o nome de usuário rodando o programa 224 | * UM : Tem o valor 1 225 | * FRANGO : Tem o valor nulo 226 | # Funcionamento, comportamento e características da implementação 227 | O shell, que é responsável pelo gerenciamento da execução de código BirlScript, tem dois modos de operação : 228 | * Um modo interativo, onde comandos podem ser executados imediatamente (chamado REPL, *Read Eval Print Loop*) 229 | * O modo normal, que executa a função global, a função principal e encerra o programa. Nesse caso, todo o programa já deve estar escrito em algum arquivo que é passado para o shell ou como argumento pro programa (com o switch `-s`) 230 | 231 | Quando uma linha de entrada, ou *input* é passada para o contexto para a evaluação, uma série de processos são feitos e o resultado depende do modo de operação descrito acima. Para ambos os casos, os passos, em geral, são : 232 | `Lexer -> Parser -> Compiler -> Máquina Virtual` 233 | 234 | ## Lexer 235 | O lexer simplesmente separar o *input* em vários *tokens*, que ajudam o parser a construir uma representação abstrata do que o programa representa. Por exemplo, 236 | ``` 237 | 2 + "texto" + variável 238 | ``` 239 | depois de passar pelo Lexer se transforma em : 240 | ``` 241 | Int(2), Operador(+), Texto("texto"), Operador(+), Símbolo("variável") 242 | ``` 243 | 244 | Os tipos diferentes de Tokens são : 245 | * Símbolos : Um nome de uma variável ou um comando incorreto 246 | * Valor : Que pode ser um Texto, um Inteiro ou Número (ainda não é possível ter literais de Lista) 247 | * Operador : Um operador matemático (e.g. +) ou um Parêntesis 248 | * Pontuação : vírgula e "dois pontos" (:) 249 | * *Frases-chave* : São como os símbolos, mas "palavras-chave" (só que com múltiplas palavras) que já são conhecidas, como JAULA, e podem ser representadas por um valor menor e definido, como um enum. Pra isso é usado o enum `KeyPhrase`. 250 | * Comentário : Um comentário, como em qualquer outra linguagem, serve pra deixar uma anotação ou mensagem sem que ela seja interpretada pela linguagem/compilador. No caso de BirlScript, o comentário é definido por `#` e a linha acaba quando esse caractere é encontrado 251 | * Nova linha (\n) : Denota uma quebra de linha 252 | * Nada : Quando, por exemplo, é pedido o próximo Token mas o input já não tem mais nada pra oferecer. 253 | 254 | O Lexer entrega um Token de cada vez baseado num *offset*, que diz onde o Lexer deve começar a procurar na string de input. Quando o *tokenizing* é finalizado (isso é, o ato de extrair um Token), o offset é modificado pra refletir a posição do próximo Token (se houver). Dessa maneira o Parser por requisitar somente os Tokens necessários (no caso de um erro, por exemplo, os outros Tokens seriam descartados e tempo seria perdido) e também pelo fato de a função específica que pede pelo próximo Token ser dona do objeto e poder mover valores, o que ~~não seria possível~~ seria bem mais complicado por conta de "limitações" que Rust impõe. 255 | 256 | ## Parser 257 | O parser é o módulo que transforma os Tokens em informação útil que pode ser compilada e, então, executada pela VM. Nessa implementação o parser é 258 | *stateless*, isso é, não mantem registro de nenhum estado. Isso significa que, com o mesmo input (e o mesmo offset), o resultado 259 | ~~deveria~~ vai ser sempre o mesmo. 260 | 261 | Dependendo do input passado por parser, 3 possíveis respostas são dadas: 262 | ### Início de uma função 263 | Nesse caso a declaração de uma função é retornada. Essa declaração inclui o nome e os parâmetros definidos no input conforme definidos 264 | pela especificação mais acima 265 | ### Fim de uma função 266 | Só é retornado algo sinalizando que foi pedido o fim da função. Os casos de esse fim ser inválido não são responsabilidade do parser 267 | ### Um comando 268 | Comandos, conforme explicado na especificação, seguem uma certa sintaxe, exceto por um único comando que *oficialmente* só existe 269 | no modo interativo de execução, que é o *DebugPrint*. Esse comando não possui um nome, em vez disso o parser entende como 270 | uma chamada pra esse comando quando vê uma expressão *crua* em vez de um comando ou *keyphrase* que signifique alguma coisa. 271 | Isso é útil pro modo interativo porque te permite ver o resultado de expressões sem digitar muito (e com informação adicional). 272 | 273 | ## Compiler 274 | O compilador possui mais complexidade que o parser e o lexer em termos de funções e responsabilidades. Diferente do parser, 275 | o compilador guarda uma série de informações e é ele que decide o que é válido e o que não dependendo de uma série de fatores, 276 | um deles sendo o *Scope*. 277 | *Scope* tem vários sentidos diferentes na codebase do BirlScript dependendo do que se trata, mas todos esses sentidos são, 278 | de certa forma, parecidos. Pra mim um Scope é um bloco (como uma caixa) que engloba alguma coisa (ou várias dessas coisas). 279 | O corpo de uma função, por exemplo, é tratado como um Scope, e variáveis definidas dentro dessa função só existem dentro 280 | dessa mesma função. Blocos de código como condicionais e loops também são Scopes, e variáveis definidas dentro desses Scopes 281 | só existem dentro deles. O compilador guarda as definições de variáveis dentro desses Scopes. Quando se é necessário procurar 282 | por um *símbolo*, ou um nome, a procura é feita do Scope mais recente para o mais velho, de forma que as variáveis mais recentes 283 | sobreponham as mais antigas. Uma informação que tanto as variáveis declaradas quanto os Scopes guardam é a respeito de estarem no Scope 284 | global, isso é, fora de qualquer função. Isso é importante pra gerar o código de acesso a essas variáveis corretamente. 285 | 286 | O compilador também guarda informação sobre as funções (e plugins) declaradas. Essa informação é sincronizada com a VM de forma 287 | que o compilador só guarda o "endereço" pra função e como acarretar a sua execução. 288 | 289 | Para a execução de funções normais, ou como elas são chamadas internamente, *source functions*, os argumentos são processados 290 | da esquerda pra direita e escritos para os endereços 1 + n (a primeira posição, isso é, o endereço 0 é a variável que guarda 291 | o valor de retorno da última função, TREZE) da *última* função que ainda não está sendo executada, isso é, ainda não tá pronta. 292 | Mais sobre isso na parte da máquina virtual. 293 | 294 | 295 | Para a execução de plugins, o compilador processa todos os argumentos da esquerda pra direita e coloca os resultados numa pilha 296 | intermediária. No momento da execução, n argumentos são retirados da pilha e usados pra chamar a função definida como plugin. 297 | ### Plugins 298 | São funções definidas internamente e incluidos com o interpretador. Como é código nativo, plugins podem trazer melhoras de performance, 299 | mas também as mensagens de erro não são de muita ajuda. *Crashes* e erros de memória também podem acontecer devido ao código 300 | não ser gerenciado pelo BirlScript diretamente (como se isso fosse adiantar alguma coisa). 301 | 302 | No momento da declaração do plugin, uma lista de argumentos esperados é passado pro compilador que guarda essa informação, que 303 | é usada pra garantir que o plugin receba a quantidade (e o tipo certo) de argumentos que ela espera. 304 | 305 | Um plugin tem acesso de leitura e escrita à máquina virtual, ou seja, tem o poder de acessar e mudar o valor de variáveis existentes. 306 | Não é possível criar novas variáveis acessíveis pras outras funções por várias razões: 307 | * Criar um símbolo e ligar ele a um endereço (isso é, criar uma variável) requer acesso ao compilador 308 | * Não é possível declarar variáveis globais dentro de uma função nem nas funções source, e variáveis de dentro das funções 309 | não são acessíveis de qualquer forma. 310 | 311 | Para a criação de variáveis globais por meio de plugins (mas não exatamente), módulos são usados. 312 | 313 | ### Módulos 314 | São como bibliotecas que podem carregar definições de funções, plugins e variáveis globais. Essas definições são feitas pelo 315 | contexto no momento da inclusão do módulo. Módulos podem ser incluidos por código (embora ainda não seja possível, só em teoria), 316 | ou com acesso direto ao contexto. 317 | 318 | A *biblioteca padrão* inclui as variáveis padrão definidas na especificação, assim como as funções e plugins necessários. 319 | Esse módulo é incluido por padrão mas pode ser ignorado com uma *flag* pela command line. 320 | 321 | ## A máquina virtual 322 | O que realmente executa o código e "faz a mágica acontecer" (se é que existe alguma mágica nisso aqui). A VM é responsável por 323 | guardar algumas informações e alterar o próprio estado conforme executa instruções. Essa lista de instruções não vai ficar 324 | disponível aqui porque são muitas, a descrição da maioria é bem pequena e já existe uma certa documentação na própria declaração 325 | de cada uma. 326 | 327 | A VM é composta por uma série de componentes, mas além disso ela guarda o *corpo* das funções compiladas (pra facilitar o 328 | acesso no momento da execução) e as funções internas dos plugins definidos. Os componentes da VM são: 329 | 330 | ### Callstack 331 | A callstack é uma pilha de *Frame*s, o último pronto sendo o que está sendo executado atualmente, o último *não-pronto* 332 | a próxima função a ser executada (ainda em preparação) e o primeiro a função global. 333 | 334 | Um frame é a representação individual de uma função em execução. Por exemplo, uma mesma função (que compartilha o mesmo corpo) 335 | pode ter dois Frames diferentes dependendo da direção que a execução dela tomou, e isso é um detalhe importante em casos como 336 | recursão. O frame guardas as variáveis especiais declaras na execução, a *stack* contendo os valores, um *PC* que aponta pra 337 | qual instrução na função desse Frame é a próxima a ser executada, uma última comparação (que é usada na execução de condicionais), 338 | um *skipping level*, que é usado em condicionais (incluindo loops) pra ignorar instruções até que se deva parar de pular instruções 339 | e *labels*, que guardam informações sobre loops em execução, como por exemplo o PC de início pra que seja possível voltar do 340 | topo a cada iteração. 341 | 342 | ### Registradores 343 | São algumas "variáveis" que a VM gerencia e usa pra algumas coisas. Os registradores não fazem parte da linguagem e não são 344 | acessíveis normalmente, então não fazem parte da especificação e dependem da implementação. Nessa, em específico, existem: 345 | * math_a e math_b : São usados pra computar expressões. Pra operação de adição, por exemplo, é feito `math_b = math_a + math_b`, 346 | isso é, o resultado sempre fica em math_b. A ordem sempre é `a op b`, exceto no caso de Texto onde a primeira operação é 347 | assim e as subsequentes são b + a. 348 | * intermediate : Intermediário, e seu uso principal é receber o valor de variáveis lidas pela VM antes de ser colocado em 349 | math_a ou math_b 350 | * secondary : Usado em operações com listas. Enquanto o intermediário recebe um valor lido, o secundário mantem guardado o 351 | endereço da lista. 352 | * first_operation : Como explicado no math_*, isso só possui efeito em operações em strings e define se é a primeira operação 353 | sendo executada. 354 | * next_*_index : Próxima ID pro corpo de uma função ou pra um plugin. 355 | * is_interactive e has_quit : bools que refletem o estado atual da VM. 356 | * default_stack_size : Capacidade padrão a ser usada nas stacks dos próximos Frames criados. 357 | 358 | ### *Special Storage* 359 | São onde são guardados os valores *especiais*, que em BirlScript isso significa que são valores de tamanho variável e são 360 | mantidos na *heap*, ou seja, com memória dinâmica. Todos os valores mantidos aqui possuem uma ID, e é por ela que eles são 361 | acessados. Não existe qualquer tipo de *reference counting*, só um tipo de garbage collecting, que limpa as variáveis especiais 362 | declaradas dentro de um Frame quando a execução do mesmo termina. 363 | 364 | ### Stdout e Stdin 365 | São a entrada e saída padrão (de onde o input vem e pra onde o output vai, respectivamente. Não confunda esse input com o que 366 | vai pro lexer/parser, por exemplo. Esse input é o que é digitado no console quando se pede algum input, por exemplo). Normalmente 367 | essas duas *bindings* apontam pras *streams* convencionais que o sistema operacional oferece, mas quando Birl é usado como 368 | uma biblioteca, isso facilita dar input ou receber o que é output sem *fuckery* adicional. 369 | -------------------------------------------------------------------------------- /birl/src/parser.rs: -------------------------------------------------------------------------------- 1 | use context::RawValue; 2 | 3 | #[cfg(target_pointer_width = "64")] 4 | pub type IntegerType = i64; 5 | 6 | #[cfg(target_pointer_width = "32")] 7 | pub type IntegerType = i32; 8 | 9 | const COMMENT_CHARACTER : char = '#'; 10 | 11 | #[derive(Debug, Clone, Copy, PartialEq)] 12 | pub enum KeyPhrase { 13 | FunctionStart, 14 | FunctionEnd, 15 | PrintLn, 16 | Print, 17 | PrintDebug, 18 | Quit, 19 | Return, 20 | Declare, 21 | Set, 22 | Compare, 23 | EndSubScope, 24 | ExecuteIfEqual, 25 | ExecuteIfNotEqual, 26 | ExecuteIfEqualOrLess, 27 | ExecuteIfLess, 28 | ExecuteIfEqualOrGreater, 29 | ExecuteIfGreater, 30 | ExecuteWhileEqual, 31 | ExecuteWhileNotEqual, 32 | ExecuteWhileEqualOrLess, 33 | ExecuteWhileLess, 34 | ExecuteWhileGreater, 35 | ExecuteWhileEqualOrGreater, 36 | RangeLoop, 37 | Call, 38 | GetStringInput, 39 | GetNumberInput, 40 | GetIntegerInput, 41 | IntoString, 42 | ConvertToInt, 43 | ConvertToNum, 44 | TypeInt, 45 | TypeNum, 46 | TypeStr, 47 | TypeList, 48 | MakeNewList, 49 | QueryListSize, 50 | AddListElement, 51 | RemoveListElement, 52 | IndexList, 53 | BreakScope, 54 | SkipNextIteration, 55 | } 56 | 57 | impl KeyPhrase { 58 | pub fn matches(src : &str) -> Option { 59 | match src { 60 | "JAULA" => Some(KeyPhrase::FunctionStart), 61 | "SAINDO DA JAULA" => Some(KeyPhrase::FunctionEnd), 62 | "BIRL" => Some(KeyPhrase::Return), 63 | "NUM VAI DA NAO" | 64 | "NUM VAI DÁ NAO" | 65 | "NUM VAI DA NÃO" | 66 | "NUM VAI DÁ NÃO" => Some(KeyPhrase::Quit), 67 | "CE QUER VER" | 68 | "CÊ QUER VER" => Some(KeyPhrase::Print), 69 | "CE QUER VER ISSO" | 70 | "CÊ QUER VER ISSO" => Some(KeyPhrase::PrintLn), 71 | "VEM" => Some(KeyPhrase::Declare), 72 | "BORA" => Some(KeyPhrase::Set), 73 | "TRAPÉZIO DESCENDENTE" | "TRAPEZIO DESCENDENTE" => Some(KeyPhrase::TypeNum), 74 | "FIBRA" => Some(KeyPhrase::TypeStr), 75 | "BATATA DOCE" => Some(KeyPhrase::TypeInt), 76 | "LISTA" => Some(KeyPhrase::TypeList), 77 | "E ELE QUE A GENTE QUER" | 78 | "É ELE QUE A GENTE QUER" => Some(KeyPhrase::Compare), 79 | "FIM" => Some(KeyPhrase::EndSubScope), 80 | "E HORA DO" | "É HORA DO" => Some(KeyPhrase::Call), 81 | "E ELE MEMO" | "É ELE MEMO" => Some(KeyPhrase::ExecuteIfEqual), 82 | "NUM E ELE" | "NUM É ELE" => Some(KeyPhrase::ExecuteIfNotEqual), 83 | "E MAIOR" | "É MAIOR" => Some(KeyPhrase::ExecuteIfGreater), 84 | "É MENOR" | "E MENOR" => Some(KeyPhrase::ExecuteIfLess), 85 | "MENOR OU E MEMO" | "MENOR OU É MEMO" => Some(KeyPhrase::ExecuteIfEqualOrLess), 86 | "MAIOR OU E MEMO" | "MAIOR OU É MEMO" => Some(KeyPhrase::ExecuteIfEqualOrGreater), 87 | "FALA AI" | "FALA AÍ" => Some(KeyPhrase::GetStringInput), 88 | "FALA UM NÚMERO" | "FALA UM NUMERO" => Some(KeyPhrase::GetNumberInput), 89 | "FALA UM INTEIRO" => Some(KeyPhrase::GetIntegerInput), 90 | "MUDA PRA TEXTO" => Some(KeyPhrase::IntoString), 91 | "MUDA PRA NUMERO" | "MUDA PRA NÚMERO" => Some(KeyPhrase::ConvertToNum), 92 | "MUDA PRA INTEIRO" => Some(KeyPhrase::ConvertToInt), 93 | "ENQUANTO É MEMO" | "ENQUANTO E MEMO" => Some(KeyPhrase::ExecuteWhileEqual), 94 | "ENQUANTO NUM E ELE" | "ENQUANTO NUM É ELE" => Some(KeyPhrase::ExecuteWhileNotEqual), 95 | "ENQUANTO E MENOR" | "ENQUANTO É MENOR" => Some(KeyPhrase::ExecuteWhileLess), 96 | "ENQUANTO MENOR OU E MEMO" | "ENQUANTO MENOR OU É MEMO" => Some(KeyPhrase::ExecuteWhileEqualOrLess), 97 | "ENQUANTO E MAIOR" | "ENQUANTO É MAIOR" => Some(KeyPhrase::ExecuteWhileGreater), 98 | "ENQUANTO MAIOR OU E MEMO" | "ENQUANTO MAIOR OU É MEMO" => Some(KeyPhrase::ExecuteWhileEqualOrGreater), 99 | "REPETE" => Some(KeyPhrase::RangeLoop), 100 | "FAZ UMA LISTA" => Some(KeyPhrase::MakeNewList), 101 | "FALA O TAMANHO" => Some(KeyPhrase::QueryListSize), 102 | "POE ISSO AQUI" | "PÕE ISSO AQUI" => Some(KeyPhrase::AddListElement), 103 | "TIRA ESSE" => Some(KeyPhrase::RemoveListElement), 104 | "ME DA ESSE" | "ME DÁ ESSE" => Some(KeyPhrase::IndexList), 105 | "PARA AQUI" => Some(KeyPhrase::BreakScope), 106 | "VAI PRO PROXIMO" | "VAI PRO PRÓXIMO" => Some(KeyPhrase::SkipNextIteration), 107 | _ => None, 108 | } 109 | } 110 | } 111 | 112 | #[derive(Debug, Clone, Copy, PartialEq)] 113 | pub enum MathOperator { 114 | Plus, 115 | Minus, 116 | Division, 117 | Multiplication, 118 | ParenthesisLeft, 119 | ParenthesisRight, 120 | } 121 | 122 | #[derive(Debug, Clone, Copy, PartialEq)] 123 | pub enum PunctuationKind { 124 | Colon, 125 | Comma, 126 | } 127 | 128 | #[derive(Debug, PartialEq)] 129 | pub enum Token { 130 | Command(KeyPhrase), 131 | Symbol(String), 132 | Text(String), 133 | Number(f64), 134 | Integer(IntegerType), 135 | Operator(MathOperator), 136 | Punctuation(PunctuationKind), 137 | Comment, 138 | NewLine, 139 | None 140 | } 141 | 142 | fn get_op(c : char) -> Option { 143 | match c { 144 | '+' => Some(MathOperator::Plus), 145 | '-' => Some(MathOperator::Minus), 146 | '/' => Some(MathOperator::Division), 147 | '*' => Some(MathOperator::Multiplication), 148 | '(' => Some(MathOperator::ParenthesisLeft), 149 | ')' => Some(MathOperator::ParenthesisRight), 150 | _ => None, 151 | } 152 | } 153 | 154 | fn get_ponct(c : char) -> Option { 155 | match c { 156 | ':' => Some(PunctuationKind::Colon), 157 | ',' => Some(PunctuationKind::Comma), 158 | _ => None, 159 | } 160 | } 161 | 162 | fn get_digit(c : char) -> Option { 163 | match c { 164 | '0' ... '9' => { 165 | let z = '0' as u8; 166 | let d = c as u8; 167 | 168 | Some(d - z) 169 | } 170 | _ => None 171 | } 172 | } 173 | 174 | fn number_token(input : &[char], offset : &mut usize, first : char) -> Result { 175 | 176 | let mut is_int = true; 177 | let mut int_val = 0 as IntegerType; 178 | let mut num_val = 0f64; 179 | let mut digits_after_dot = 0; 180 | 181 | if first == '.' { 182 | is_int = false; 183 | digits_after_dot = 1; 184 | } else { 185 | int_val = match get_digit(first) { 186 | Some(d) => d as IntegerType, 187 | None => return Err("Internal error : First char to number_token is not a digit or a dot".to_owned()), 188 | }; 189 | } 190 | 191 | loop { 192 | if *offset >= input.len() { 193 | break; 194 | } 195 | 196 | let cur = input[*offset]; 197 | 198 | if cur == COMMENT_CHARACTER { 199 | break; 200 | } 201 | 202 | if cur == '.' { 203 | if !is_int { 204 | return Err(String::from("Dois pontos aparecem no literal de número")); 205 | } else { 206 | is_int = false; 207 | num_val = int_val as f64; 208 | digits_after_dot = 1; 209 | } 210 | } else { 211 | match cur { 212 | '0'...'9' => { 213 | let digit = get_digit(cur).unwrap(); 214 | 215 | if is_int { 216 | int_val *= 10; 217 | int_val += digit as IntegerType; 218 | } else { 219 | let diff = 0.1f64.powi(digits_after_dot); 220 | num_val += diff * (digit as f64); 221 | digits_after_dot += 1; 222 | } 223 | } 224 | _ => break, 225 | } 226 | } 227 | 228 | *offset += 1; 229 | } 230 | 231 | if is_int { 232 | Ok(Token::Integer(int_val)) 233 | } else { 234 | Ok(Token::Number(num_val)) 235 | } 236 | } 237 | 238 | fn text_token(input : &[char], offset : &mut usize) -> Result { 239 | let mut content = String::new(); 240 | 241 | let mut last_was_escape = false; 242 | 243 | loop { 244 | if *offset >= input.len() { 245 | break; 246 | } 247 | 248 | let cur = input[*offset]; 249 | *offset += 1; 250 | 251 | if last_was_escape { 252 | match cur { 253 | '\\' | 254 | '\"' => content.push(cur), 255 | 't' => content.push('\t'), 256 | 'n' => content.push('\n'), 257 | 'r' => content.push('\r'), 258 | _ => {} // warn? 259 | } 260 | 261 | last_was_escape = false; 262 | } else { 263 | match cur { 264 | '\"' => break, 265 | '\\' => last_was_escape = true, 266 | _ => content.push(cur), 267 | } 268 | } 269 | } 270 | 271 | Ok(Token::Text(content)) 272 | } 273 | 274 | fn symbol_token(input : &[char], offset : &mut usize, first : char) -> Result { 275 | let mut result = String::new(); 276 | 277 | result.push(first); 278 | 279 | let mut first_word = true; 280 | let mut first_char = false; 281 | 282 | loop { 283 | if *offset >= input.len() { 284 | break; 285 | } 286 | 287 | let cur = input[*offset]; 288 | 289 | if cur == COMMENT_CHARACTER || cur == '\n' || cur == '\r' { 290 | break; 291 | } 292 | 293 | if cur == ' ' { 294 | if first_word { 295 | if let Some(kp) = KeyPhrase::matches(result.as_str()) { 296 | return Ok(Token::Command(kp)); 297 | } 298 | 299 | first_word = false; 300 | } 301 | 302 | if first_char { 303 | break; 304 | } else { 305 | first_char = true; 306 | } 307 | } else { 308 | if let Some(_) = get_op(cur) { 309 | break; 310 | } 311 | 312 | if let Some(_) = get_digit(cur) { 313 | if first_char { 314 | break; 315 | } 316 | } 317 | 318 | if let Some(_) = get_ponct(cur) { 319 | break; 320 | } 321 | 322 | match cur { 323 | '.' => break, 324 | _ => { 325 | if first_char { 326 | result.push(' '); 327 | first_char = false; 328 | } 329 | 330 | result.push(cur); 331 | }, 332 | } 333 | } 334 | 335 | *offset += 1; 336 | } 337 | 338 | if let Some(kp) = KeyPhrase::matches(result.as_str()) { 339 | Ok(Token::Command(kp)) 340 | } else { 341 | Ok(Token::Symbol(result)) 342 | } 343 | } 344 | 345 | pub fn next_token(input : &[char], offset : &mut usize) -> Result { 346 | if *offset >= input.len() { 347 | return Ok(Token::None); 348 | } 349 | 350 | loop { 351 | if input[*offset] != ' ' && input[*offset] != '\t' { 352 | break; 353 | } 354 | 355 | *offset += 1; 356 | } 357 | 358 | let first_char = input[*offset]; 359 | *offset += 1; 360 | 361 | if first_char == COMMENT_CHARACTER { 362 | return Ok(Token::Comment); 363 | } 364 | 365 | if first_char == '\n' || first_char == '\r'{ 366 | return Ok(Token::NewLine); 367 | } 368 | 369 | if let Some(op) = get_op(first_char) { 370 | return Ok(Token::Operator(op)); 371 | } 372 | 373 | if let Some(p) = get_ponct(first_char) { 374 | return Ok(Token::Punctuation(p)); 375 | } 376 | 377 | if let Some(_) = get_digit(first_char) { 378 | return number_token(input, offset, first_char); 379 | } 380 | 381 | if first_char == '.' { 382 | return number_token(input, offset, first_char); 383 | } 384 | 385 | if first_char == '\"' { 386 | return text_token(input, offset); 387 | } 388 | 389 | symbol_token(input, offset, first_char) 390 | } 391 | 392 | #[derive(Debug, Clone, Copy, PartialEq)] 393 | pub enum TypeKind { 394 | Integer, 395 | Number, 396 | Text, 397 | List, 398 | Null, 399 | } 400 | 401 | impl TypeKind { 402 | fn from_kp(kp : KeyPhrase) -> Option { 403 | match kp { 404 | KeyPhrase::TypeInt => Some(TypeKind::Integer), 405 | KeyPhrase::TypeNum => Some(TypeKind::Number), 406 | KeyPhrase::TypeStr => Some(TypeKind::Text), 407 | KeyPhrase::TypeList => Some(TypeKind::List), 408 | _ => None, 409 | } 410 | } 411 | } 412 | 413 | #[derive(Debug, PartialEq, Clone)] 414 | pub struct FunctionParameter { 415 | pub name : String, 416 | pub kind : TypeKind, 417 | } 418 | 419 | impl FunctionParameter { 420 | pub fn from(name : String, kind : TypeKind) -> FunctionParameter { 421 | FunctionParameter { 422 | name, 423 | kind 424 | } 425 | } 426 | } 427 | 428 | #[derive(Debug, PartialEq)] 429 | pub struct FunctionDeclaration { 430 | pub name : String, 431 | pub arguments : Vec, 432 | } 433 | 434 | impl FunctionDeclaration { 435 | pub fn from(name : String) -> FunctionDeclaration { 436 | FunctionDeclaration { 437 | name, 438 | arguments: vec![] 439 | } 440 | } 441 | } 442 | 443 | #[derive(Debug, PartialEq)] 444 | pub enum ExpressionNode { 445 | Value(RawValue), 446 | Symbol(String), 447 | Operator(MathOperator), 448 | } 449 | 450 | #[derive(Debug, PartialEq)] 451 | pub struct Expression { 452 | pub nodes : Vec, 453 | pub has_symbols : bool, 454 | } 455 | 456 | impl Expression { 457 | pub fn new() -> Expression { 458 | Expression { 459 | nodes: vec![], 460 | has_symbols: false, 461 | } 462 | } 463 | } 464 | 465 | #[derive(Clone, Copy, Debug, PartialEq)] 466 | pub enum CommandKind { 467 | Return, 468 | Quit, 469 | Print, 470 | PrintLn, 471 | PrintDebug, 472 | Declare, 473 | Set, 474 | Compare, 475 | EndSubScope, 476 | ExecuteIfEqual, 477 | ExecuteIfNotEqual, 478 | ExecuteIfEqualOrLess, 479 | ExecuteIfLess, 480 | ExecuteIfEqualOrGreater, 481 | ExecuteIfGreater, 482 | Call, 483 | GetStringInput, 484 | GetNumberInput, 485 | GetIntegerInput, 486 | ConvertToNum, 487 | ConvertToInt, 488 | IntoString, 489 | ExecuteWhileEqual, 490 | ExecuteWhileNotEqual, 491 | ExecuteWhileEqualOrLess, 492 | ExecuteWhileLess, 493 | ExecuteWhileGreater, 494 | ExecuteWhileEqualOrGreater, 495 | RangeLoop, 496 | MakeNewList, 497 | QueryListSize, 498 | AddListElement, 499 | RemoveListElement, 500 | IndexList, 501 | BreakScope, 502 | SkipNextIteration, 503 | } 504 | 505 | impl CommandKind { 506 | fn from_kp(kp : KeyPhrase) -> Option { 507 | match kp { 508 | KeyPhrase::Print => Some(CommandKind::Print), 509 | KeyPhrase::PrintLn => Some(CommandKind::PrintLn), 510 | KeyPhrase::PrintDebug => Some(CommandKind::PrintDebug), 511 | KeyPhrase::Return => Some(CommandKind::Return), 512 | KeyPhrase::Quit => Some(CommandKind::Quit), 513 | KeyPhrase::Declare => Some(CommandKind::Declare), 514 | KeyPhrase::Set => Some(CommandKind::Set), 515 | KeyPhrase::Compare => Some(CommandKind::Compare), 516 | KeyPhrase::EndSubScope => Some(CommandKind::EndSubScope), 517 | KeyPhrase::ExecuteIfEqual => Some(CommandKind::ExecuteIfEqual), 518 | KeyPhrase::ExecuteIfNotEqual => Some(CommandKind::ExecuteIfNotEqual), 519 | KeyPhrase::ExecuteIfEqualOrGreater => Some(CommandKind::ExecuteIfEqualOrGreater), 520 | KeyPhrase::ExecuteIfGreater => Some(CommandKind::ExecuteIfGreater), 521 | KeyPhrase::ExecuteIfEqualOrLess => Some(CommandKind::ExecuteIfEqualOrLess), 522 | KeyPhrase::ExecuteIfLess => Some(CommandKind::ExecuteIfLess), 523 | KeyPhrase::Call => Some(CommandKind::Call), 524 | KeyPhrase::GetStringInput => Some(CommandKind::GetStringInput), 525 | KeyPhrase::GetNumberInput => Some(CommandKind::GetNumberInput), 526 | KeyPhrase::IntoString => Some(CommandKind::IntoString), 527 | KeyPhrase::ConvertToInt => Some(CommandKind::ConvertToInt), 528 | KeyPhrase::ConvertToNum => Some(CommandKind::ConvertToNum), 529 | KeyPhrase::GetIntegerInput => Some(CommandKind::GetIntegerInput), 530 | KeyPhrase::ExecuteWhileEqual => Some(CommandKind::ExecuteWhileEqual), 531 | KeyPhrase::ExecuteWhileNotEqual => Some(CommandKind::ExecuteWhileNotEqual), 532 | KeyPhrase::ExecuteWhileEqualOrLess => Some(CommandKind::ExecuteWhileEqualOrLess), 533 | KeyPhrase::ExecuteWhileLess => Some(CommandKind::ExecuteWhileLess), 534 | KeyPhrase::ExecuteWhileGreater => Some(CommandKind::ExecuteWhileGreater), 535 | KeyPhrase::ExecuteWhileEqualOrGreater => Some(CommandKind::ExecuteWhileEqualOrGreater), 536 | KeyPhrase::RangeLoop => Some(CommandKind::RangeLoop), 537 | KeyPhrase::MakeNewList => Some(CommandKind::MakeNewList), 538 | KeyPhrase::QueryListSize => Some(CommandKind::QueryListSize), 539 | KeyPhrase::AddListElement => Some(CommandKind::AddListElement), 540 | KeyPhrase::RemoveListElement => Some(CommandKind::RemoveListElement), 541 | KeyPhrase::IndexList => Some(CommandKind::IndexList), 542 | KeyPhrase::BreakScope => Some(CommandKind::BreakScope), 543 | KeyPhrase::SkipNextIteration => Some(CommandKind::SkipNextIteration), 544 | _ => None, 545 | } 546 | } 547 | } 548 | 549 | #[derive(Clone, Copy, Debug)] 550 | enum CommandArgumentKind { 551 | Name, 552 | Expression 553 | } 554 | 555 | struct CommandInfo { 556 | min_args : u32, 557 | max_args : i32, 558 | expected_args : Vec 559 | } 560 | 561 | impl CommandInfo { 562 | 563 | fn from(min_args : u32, max_args : i32, expected_args : Vec) -> CommandInfo { 564 | CommandInfo { 565 | min_args, 566 | max_args, 567 | expected_args 568 | } 569 | } 570 | 571 | fn from_kind(kind : CommandKind) -> CommandInfo { 572 | match kind { 573 | CommandKind::Quit => CommandInfo::from(0, 0, vec![]), 574 | CommandKind::Return => CommandInfo::from(0, 1, 575 | vec![CommandArgumentKind::Expression]), 576 | CommandKind::Print => CommandInfo::from(1, -1, 577 | vec![CommandArgumentKind::Expression]), 578 | CommandKind::PrintLn => CommandInfo::from(0, -1, 579 | vec![CommandArgumentKind::Expression]), 580 | CommandKind::PrintDebug => CommandInfo::from(1, 1, 581 | vec![CommandArgumentKind::Expression]), 582 | CommandKind::Declare => { 583 | CommandInfo::from(1, 2, vec![CommandArgumentKind::Name, 584 | CommandArgumentKind::Expression]) 585 | } 586 | CommandKind::Set => { 587 | CommandInfo::from(2, 2, vec![CommandArgumentKind::Name, 588 | CommandArgumentKind::Expression]) 589 | } 590 | CommandKind::Compare => { 591 | CommandInfo::from(2, 2, vec![CommandArgumentKind::Expression, 592 | CommandArgumentKind::Expression]) 593 | } 594 | CommandKind::EndSubScope => { 595 | CommandInfo::from(0, 0, vec![]) 596 | } 597 | CommandKind::Call => { 598 | CommandInfo::from(1, -1, vec![CommandArgumentKind::Name, 599 | CommandArgumentKind::Expression]) 600 | } 601 | CommandKind::ExecuteIfEqual | 602 | CommandKind::ExecuteIfNotEqual | 603 | CommandKind::ExecuteIfLess | 604 | CommandKind::ExecuteIfGreater | 605 | CommandKind::ExecuteIfEqualOrLess | 606 | CommandKind::ExecuteIfEqualOrGreater => { 607 | CommandInfo::from(0, 0, vec![]) 608 | } 609 | CommandKind::ExecuteWhileEqual | 610 | CommandKind::ExecuteWhileNotEqual | 611 | CommandKind::ExecuteWhileLess | 612 | CommandKind::ExecuteWhileGreater | 613 | CommandKind::ExecuteWhileEqualOrLess | 614 | CommandKind::ExecuteWhileEqualOrGreater => { 615 | CommandInfo::from(2, 2, vec![CommandArgumentKind::Expression, 616 | CommandArgumentKind::Expression]) 617 | } 618 | CommandKind::GetStringInput | CommandKind::GetNumberInput | CommandKind::IntoString | 619 | CommandKind::ConvertToNum | CommandKind::ConvertToInt | CommandKind::GetIntegerInput => { 620 | CommandInfo::from(1, 1, vec![CommandArgumentKind::Name]) 621 | } 622 | CommandKind::RangeLoop => { 623 | // First is the variable, second is the start, third is the end, fourth (optional) is the skipping 624 | CommandInfo::from(3, 4, vec![CommandArgumentKind::Name, 625 | CommandArgumentKind::Expression, CommandArgumentKind::Expression, 626 | CommandArgumentKind::Expression]) 627 | } 628 | CommandKind::MakeNewList => { 629 | CommandInfo::from(1, 1, vec![CommandArgumentKind::Name]) 630 | } 631 | CommandKind::QueryListSize => { 632 | CommandInfo::from(2, 2, vec![CommandArgumentKind::Name, CommandArgumentKind::Name]) 633 | } 634 | CommandKind::AddListElement => { 635 | CommandInfo::from(2, 3, vec![CommandArgumentKind::Name, CommandArgumentKind::Expression, 636 | CommandArgumentKind::Expression]) 637 | } 638 | CommandKind::RemoveListElement => { 639 | CommandInfo::from(2, 2, vec![CommandArgumentKind::Name, CommandArgumentKind::Expression]) 640 | } 641 | CommandKind::IndexList => { 642 | CommandInfo::from(3, 3, vec![CommandArgumentKind::Name, CommandArgumentKind::Expression, 643 | CommandArgumentKind::Name]) 644 | } 645 | CommandKind::BreakScope | CommandKind::SkipNextIteration => CommandInfo::from(0, 0, vec![]), 646 | } 647 | } 648 | } 649 | 650 | #[derive(Debug)] 651 | pub enum CommandArgument { 652 | Name(String), 653 | Expression(Expression), 654 | } 655 | 656 | #[derive(Debug)] 657 | pub struct Command { 658 | pub kind : CommandKind, 659 | pub arguments : Vec, 660 | } 661 | 662 | #[derive(Debug)] 663 | pub enum ParserResult { 664 | FunctionStart(FunctionDeclaration), 665 | FunctionEnd, 666 | Command(Command), 667 | Nothing, 668 | } 669 | 670 | fn parse_parameter(src : &[char], offset : &mut usize) -> Result, String> { 671 | let name = match next_token(src, offset) { 672 | Ok(Token::Symbol(s)) => s, 673 | Ok(Token::Operator(MathOperator::ParenthesisRight)) => return Ok(None), 674 | Ok(t) => return Err(format!("Esperado um nome pro parâmetro, encontrado {:?}", t)), 675 | Err(e) => return Err(e) 676 | }; 677 | 678 | match next_token(src, offset) { 679 | Ok(Token::Punctuation(PunctuationKind::Colon)) => {} // OK, 680 | Ok(t) => return Err(format!("Esperado um : depois do nome, encontrado {:?}", t)), 681 | Err(e) => return Err(e) 682 | }; 683 | 684 | let kind = match next_token(src, offset) { 685 | Ok(Token::Command(kp)) => { 686 | match TypeKind::from_kp(kp) { 687 | Some(t) => t, 688 | None => return Err(format!("Esperado um tipo pro parâmetro, mas {:?} não existe", kp)), 689 | } 690 | } 691 | Ok(t) => return Err(format!("Esperado um tipo pro parâmetro, encontrado {:?}", t)), 692 | Err(e) => return Err(e) 693 | }; 694 | 695 | Ok(Some(FunctionParameter::from(name, kind))) 696 | } 697 | 698 | fn parse_function(src : &[char], offset : &mut usize) -> Result { 699 | 700 | // Next token is the function name 701 | 702 | let name = match next_token(src, offset) { 703 | Ok(t) => { 704 | match t { 705 | Token::Symbol(name) => name, 706 | _ => return Err(format!("Esperado um nome pra função, encontrado um {:?}", t)) 707 | } 708 | } 709 | Err(e) => return Err(e) 710 | }; 711 | 712 | let mut func = FunctionDeclaration::from(name); 713 | 714 | match next_token(src, offset) { 715 | Ok(t) => { 716 | match t { 717 | Token::NewLine | Token::None => {} 718 | Token::Operator(MathOperator::ParenthesisLeft) => { 719 | // Argument list 720 | 721 | loop { 722 | if *offset >= src.len() { 723 | return Err("A lista de argumentos acaba incompleta".to_owned()); 724 | } 725 | 726 | let param = match parse_parameter(src, offset) { 727 | Ok(Some(p)) => p, 728 | Ok(None) => break, 729 | Err(e) => return Err(e) 730 | }; 731 | 732 | func.arguments.push(param); 733 | 734 | // Check next token 735 | 736 | match next_token(src, offset) { 737 | Ok(Token::Punctuation(PunctuationKind::Comma)) => {} // Ok 738 | Ok(Token::Operator(MathOperator::ParenthesisRight)) => break, // End 739 | Ok(t) => return Err(format!("Esperado uma vírgula ou o fim da lista de parâmetros, encontrado {:?}", t)), 740 | Err(e) => return Err(e), 741 | }; 742 | } 743 | } 744 | _ => return Err(format!("Esperado o fim da declaração ou uma lista de parâmetros, encontrado {:?}", t)), 745 | } 746 | } 747 | Err(e) => return Err(e), 748 | } 749 | 750 | Ok(ParserResult::FunctionStart(func)) 751 | } 752 | 753 | fn parse_sub_expression(src : &[char], offset : &mut usize, expr : &mut Expression, root : bool) -> Result<(), String> { 754 | 755 | let mut last_was_value; 756 | 757 | let mut dummy_offset = *offset; 758 | 759 | let first = match next_token(src, &mut dummy_offset) { 760 | Ok(t) => t, 761 | Err(e) => return Err(e), 762 | }; 763 | 764 | let mut nodes = vec![]; 765 | 766 | let mut values : Vec = vec![]; 767 | let mut operations : Vec = vec![]; 768 | let mut last_was_important = false; 769 | 770 | match first { 771 | Token::Comment | Token::None => return Ok(()), 772 | Token::Integer(i) => { 773 | last_was_value = true; 774 | 775 | if last_was_important { 776 | last_was_important = false; 777 | 778 | match values.pop() { 779 | Some(v) => nodes.push(v), 780 | None => {} 781 | } 782 | 783 | let op = match operations.pop() { 784 | Some(v) => v, 785 | None => return Err("Operations tá vazio".to_owned()), 786 | }; 787 | 788 | nodes.push(ExpressionNode::Value(RawValue::Integer(i))); 789 | nodes.push(ExpressionNode::Operator(op)); 790 | } else { 791 | values.push(ExpressionNode::Value(RawValue::Integer(i))); 792 | } 793 | } 794 | Token::Number(n) => { 795 | last_was_value = true; 796 | 797 | if last_was_important { 798 | last_was_important = false; 799 | 800 | match values.pop() { 801 | Some(v) => nodes.push(v), 802 | None => {} 803 | } 804 | 805 | let op = match operations.pop() { 806 | Some(v) => v, 807 | None => return Err("Operations tá vazio".to_owned()), 808 | }; 809 | 810 | nodes.push(ExpressionNode::Value(RawValue::Number(n))); 811 | nodes.push(ExpressionNode::Operator(op)); 812 | } else { 813 | values.push(ExpressionNode::Value(RawValue::Number(n))); 814 | } 815 | } 816 | Token::Text(t) => { 817 | last_was_value = true; 818 | 819 | values.push(ExpressionNode::Value(RawValue::Text(t))); 820 | } 821 | Token::NewLine => return Ok(()), 822 | Token::Symbol(s) => { 823 | last_was_value = true; 824 | 825 | if !expr.has_symbols { 826 | expr.has_symbols = true; 827 | } 828 | 829 | if last_was_important { 830 | last_was_important = false; 831 | 832 | match values.pop() { 833 | Some(v) => nodes.push(v), 834 | None => {} 835 | } 836 | 837 | let op = match operations.pop() { 838 | Some(v) => v, 839 | None => return Err("Operations tá vazio".to_owned()), 840 | }; 841 | 842 | nodes.push(ExpressionNode::Symbol(s)); 843 | nodes.push(ExpressionNode::Operator(op)); 844 | } else { 845 | values.push(ExpressionNode::Symbol(s)); 846 | } 847 | } 848 | Token::Operator(MathOperator::ParenthesisLeft) => { 849 | last_was_value = true; 850 | 851 | match parse_sub_expression(src, &mut dummy_offset, expr, false) { 852 | Ok(_) => {} 853 | Err(e) => return Err(e) 854 | }; 855 | } 856 | Token::Operator(MathOperator::ParenthesisRight) => { 857 | *offset = dummy_offset; 858 | 859 | return Ok(()); 860 | }, 861 | Token::Operator(o) => { 862 | match o { 863 | MathOperator::Plus | MathOperator::Minus => { 864 | // Add a zero before this 865 | values.push(ExpressionNode::Value(RawValue::Integer(0))); 866 | operations.push(o); 867 | }, 868 | _ => return Err(format!("Scope ou expressão começa com o operator unário inválido {:?}", o)), 869 | } 870 | 871 | last_was_value = false; 872 | } 873 | Token::Punctuation(p) => { 874 | match p { 875 | PunctuationKind::Comma if root => { 876 | // Ok 877 | 878 | return Ok(()); 879 | } 880 | _ => return Err(format!("A expressão deveria começar com um valor ou operador unário, mas começa com {:?}", p)), 881 | } 882 | } 883 | _ => return Err(format!("Esperado um valor ou operador na expressão, encontrado {:?}", first)), 884 | } 885 | 886 | *offset = dummy_offset; 887 | 888 | loop { 889 | if *offset >= src.len() { 890 | break; 891 | } 892 | 893 | let current = match next_token(src, &mut dummy_offset) { 894 | Ok(t) => t, 895 | Err(e) => return Err(e) 896 | }; 897 | 898 | match current { 899 | Token::None | Token::Comment => return Ok(()), 900 | Token::Integer(i) => { 901 | if last_was_value { 902 | return Err("Dois valores seguidos na expressão".to_owned()); 903 | } 904 | 905 | last_was_value = true; 906 | 907 | if last_was_important { 908 | last_was_important = false; 909 | 910 | match values.pop() { 911 | Some(v) => nodes.push(v), 912 | None => {} 913 | } 914 | 915 | let op = match operations.pop() { 916 | Some(v) => v, 917 | None => return Err("Operations tá vazio".to_owned()), 918 | }; 919 | 920 | nodes.push(ExpressionNode::Value(RawValue::Integer(i))); 921 | nodes.push(ExpressionNode::Operator(op)); 922 | } else { 923 | values.push(ExpressionNode::Value(RawValue::Integer(i))); 924 | } 925 | } 926 | Token::Number(n) => { 927 | if last_was_value { 928 | return Err("Dois valores seguidos na expressão".to_owned()); 929 | } 930 | 931 | last_was_value = true; 932 | 933 | if last_was_important { 934 | last_was_important = false; 935 | 936 | match values.pop() { 937 | Some(v) => nodes.push(v), 938 | None => {} 939 | } 940 | 941 | let op = match operations.pop() { 942 | Some(v) => v, 943 | None => return Err("Operations tá vazio".to_owned()), 944 | }; 945 | 946 | nodes.push(ExpressionNode::Value(RawValue::Number(n))); 947 | nodes.push(ExpressionNode::Operator(op)); 948 | } else { 949 | values.push(ExpressionNode::Value(RawValue::Number(n))); 950 | } 951 | } 952 | Token::Text(t) => { 953 | if last_was_value { 954 | return Err("Dois valores seguidos na expressão".to_owned()); 955 | } 956 | 957 | last_was_value = true; 958 | 959 | values.push(ExpressionNode::Value(RawValue::Text(t))); 960 | } 961 | Token::Symbol(s) => { 962 | if last_was_value { 963 | return Err("Dois valores seguidos na expressão".to_owned()); 964 | } 965 | 966 | last_was_value = true; 967 | 968 | if !expr.has_symbols { 969 | expr.has_symbols = true; 970 | } 971 | 972 | if last_was_important { 973 | last_was_important = false; 974 | 975 | match values.pop() { 976 | Some(v) => nodes.push(v), 977 | None => {} 978 | } 979 | 980 | let op = match operations.pop() { 981 | Some(v) => v, 982 | None => return Err("Operations tá vazio".to_owned()), 983 | }; 984 | 985 | nodes.push(ExpressionNode::Symbol(s)); 986 | nodes.push(ExpressionNode::Operator(op)); 987 | } else { 988 | values.push(ExpressionNode::Symbol(s)); 989 | } 990 | } 991 | Token::Operator(MathOperator::ParenthesisLeft) => { 992 | last_was_value = true; 993 | 994 | match parse_sub_expression(src, &mut dummy_offset, expr, false) { 995 | Ok(_) => {} 996 | Err(e) => return Err(e) 997 | }; 998 | } 999 | Token::Operator(MathOperator::ParenthesisRight) => { 1000 | *offset = dummy_offset; 1001 | 1002 | break 1003 | }, 1004 | Token::Operator(o) => { 1005 | if !last_was_value { 1006 | return Err("Dois operadores seguidos na expressão".to_owned()); 1007 | } 1008 | 1009 | last_was_value = false; 1010 | 1011 | last_was_important = match o { 1012 | MathOperator::Plus | MathOperator::Minus => false, 1013 | _ => true, 1014 | }; 1015 | 1016 | operations.push(o); 1017 | } 1018 | Token::Punctuation(p) => { 1019 | match p { 1020 | PunctuationKind::Comma if root => { 1021 | // Ok. Do not set offset to dummy_offset, since we want the lower calls and the parser to see the comma 1022 | 1023 | break; 1024 | } 1025 | _ => return Err(format!("Erro: {:?} no meio da expressão", p)), 1026 | } 1027 | } 1028 | Token::NewLine => break, 1029 | _ => return Err(format!("Esperado um valor ou operador na expressão, encontrado {:?}", current)), 1030 | } 1031 | 1032 | *offset = dummy_offset; 1033 | } 1034 | 1035 | if !last_was_value { 1036 | return Err("Expressão termina com um operador".to_owned()); 1037 | } 1038 | 1039 | for node in nodes { 1040 | expr.nodes.push(node); 1041 | } 1042 | 1043 | if values.len() == operations.len() { 1044 | // Ok 1045 | } else if operations.len() == values.len() - 1 { 1046 | let first = values.remove(0); 1047 | 1048 | expr.nodes.push(first); 1049 | } else { 1050 | return Err(format!("Formatação inválida da expressão resultado. Lenv : {}. lenO: {}", values.len(), operations.len())); 1051 | } 1052 | 1053 | for _ in 0..values.len() { 1054 | let val = values.remove(0); 1055 | let op = operations.remove(0); 1056 | expr.nodes.push(val); 1057 | expr.nodes.push(ExpressionNode::Operator(op)); 1058 | } 1059 | 1060 | Ok(()) 1061 | } 1062 | 1063 | fn parse_expression(src : &[char], offset : &mut usize) -> Result { 1064 | let mut expr = Expression::new(); 1065 | 1066 | match parse_sub_expression(src, offset, &mut expr, true) { 1067 | Ok(_) => Ok(expr), 1068 | Err(e) => Err(e), 1069 | } 1070 | } 1071 | 1072 | fn parse_command(src : &[char], offset : &mut usize, kp : KeyPhrase) -> Result { 1073 | let cmd_kind = match CommandKind::from_kp(kp) { 1074 | Some(k) => k, 1075 | // I don't think this will ever happen, so leave this awful message 1076 | None => return Err("Invalid KeyPhrase to command".to_owned()), 1077 | }; 1078 | 1079 | let mut cmd = Command { 1080 | kind : cmd_kind, 1081 | arguments : vec![], 1082 | }; 1083 | 1084 | let info = CommandInfo::from_kind(cmd_kind); 1085 | 1086 | let mut has_arguments = if cmd_kind == CommandKind::PrintDebug { 1087 | true 1088 | } else { 1089 | match next_token(src, offset) { 1090 | Ok(t) => { 1091 | match t { 1092 | Token::NewLine | Token::None => false, 1093 | Token::Punctuation(PunctuationKind::Colon) => true, 1094 | _ => false, 1095 | } 1096 | } 1097 | Err(e) => return Err(e), 1098 | } 1099 | }; 1100 | 1101 | let mut dummy_offset = *offset; 1102 | 1103 | match next_token(src, &mut dummy_offset) { 1104 | Ok(Token::NewLine) | Ok(Token::None) => has_arguments = false, 1105 | Ok(_) => {}, 1106 | Err(e) => return Err(e) 1107 | } 1108 | 1109 | if has_arguments { 1110 | let mut arg_index = 0usize; 1111 | let mut arg_count = 0usize; 1112 | 1113 | loop { 1114 | if *offset >= src.len() { 1115 | break; 1116 | } 1117 | 1118 | if arg_index >= info.expected_args.len() { 1119 | if info.max_args < 0 { 1120 | arg_index = info.expected_args.len() - 1; 1121 | } else { 1122 | return Err(format!("O comando espera, no máximo, apenas {} argumentos, mas mais que isso foi passado", info.max_args)); 1123 | } 1124 | } 1125 | 1126 | let expected = info.expected_args[arg_index]; 1127 | 1128 | match expected { 1129 | CommandArgumentKind::Name => { 1130 | match next_token(src, offset) { 1131 | Ok(t) => { 1132 | match t { 1133 | Token::Symbol(s) => cmd.arguments.push(CommandArgument::Name(s)), 1134 | _ => return Err(format!("O argumento espera que o argumento #{} seja um nome, mas {:?} foi encontrado", arg_count, t)), 1135 | } 1136 | } 1137 | Err(e) => return Err(e), 1138 | } 1139 | } 1140 | CommandArgumentKind::Expression => { 1141 | let expr = match parse_expression(src, offset) { 1142 | Ok(e) => e, 1143 | Err(e) => return Err(e) 1144 | }; 1145 | 1146 | cmd.arguments.push(CommandArgument::Expression(expr)); 1147 | } 1148 | } 1149 | 1150 | // Next token should be ',', or else the argument list is over 1151 | 1152 | let mut peek_offset = *offset; 1153 | 1154 | match next_token(src, &mut peek_offset) { 1155 | Ok(t) => { 1156 | match t { 1157 | Token::None | Token::NewLine => break, 1158 | Token::Punctuation(p) => { 1159 | match p { 1160 | PunctuationKind::Comma => { 1161 | *offset = peek_offset; 1162 | } // OK 1163 | _ => return Err(format!("Esperado uma vírgula ou o fim dos argumentos, mas foi encontrado {:?}", p)), 1164 | } 1165 | } 1166 | _ => return Err(format!("Esperado uma vírgula ou o fim dos argumentos, mas foi encontrado {:?}", t)), 1167 | } 1168 | } 1169 | Err(e) => return Err(e), 1170 | } 1171 | 1172 | arg_count += 1; 1173 | arg_index += 1; 1174 | } 1175 | } 1176 | 1177 | if cmd.arguments.len() < info.min_args as usize { 1178 | return Err(format!("O comando espera ao menos {} argumentos, mas {} foram passados", info.min_args, cmd.arguments.len())); 1179 | } 1180 | 1181 | Ok(ParserResult::Command(cmd)) 1182 | } 1183 | 1184 | pub fn parse_line(src : &str) -> Result { 1185 | if src.trim().is_empty() { 1186 | return Ok(ParserResult::Nothing); 1187 | } 1188 | 1189 | let chars = src.chars().collect::>(); 1190 | 1191 | // try to infer what we're parsing from the first token 1192 | 1193 | let mut offset = 0usize; 1194 | 1195 | let first = match next_token(&chars, &mut offset) { 1196 | Ok(t) => t, 1197 | Err(e) => return Err(e), 1198 | }; 1199 | 1200 | match first { 1201 | Token::Comment => Ok(ParserResult::Nothing), 1202 | Token::Command(kp) => { 1203 | match kp { 1204 | KeyPhrase::FunctionEnd => Ok(ParserResult::FunctionEnd), 1205 | KeyPhrase::FunctionStart => parse_function(&chars, &mut offset), 1206 | _ => parse_command(&chars, &mut offset, kp), 1207 | } 1208 | } 1209 | Token::Text(_) | Token::Number(_) | Token::Integer(_) | Token::Operator(MathOperator::ParenthesisLeft) => { 1210 | offset = 0; 1211 | parse_command(&chars, &mut offset, KeyPhrase::PrintDebug) 1212 | } 1213 | Token::Symbol(sym) => { 1214 | match next_token(&chars, &mut offset) { 1215 | Ok(Token::Punctuation(PunctuationKind::Colon)) => { 1216 | return Err(format!("O comando \"{}\" não existe.", sym)); 1217 | } 1218 | Ok(_) => { 1219 | offset = 0; 1220 | parse_command(&chars, &mut offset, KeyPhrase::PrintDebug) 1221 | } 1222 | Err(e) => return Err(e) 1223 | } 1224 | } 1225 | _ => Err("Linha começa com um token inválido".to_owned()), 1226 | } 1227 | } 1228 | 1229 | mod tests { 1230 | #[test] 1231 | fn functions() { 1232 | use parser::*; 1233 | 1234 | { 1235 | let src = "JAULA TESTANDO"; 1236 | 1237 | let got_func = match parse_line(src) { 1238 | Ok(ParserResult::FunctionStart(func)) => func, 1239 | Ok(res) => panic!("Era esperado uma função, recebido {:?}", res), 1240 | Err(e) => panic!("{}", e) 1241 | }; 1242 | 1243 | let expected = FunctionDeclaration::from("TESTANDO".to_owned()); 1244 | 1245 | assert_eq!(got_func, expected); 1246 | } 1247 | 1248 | { 1249 | let src = "JAULA F(ARG1 : FIBRA, ARG2 : TRAPÉZIO DESCENDENTE)"; 1250 | 1251 | let got_func = match parse_line(src) { 1252 | Ok(ParserResult::FunctionStart(func)) => func, 1253 | Ok(res) => panic!("Era esperado uma função, recebido {:?}", res), 1254 | Err(e) => panic!("{}", e) 1255 | }; 1256 | 1257 | let mut expected = FunctionDeclaration::from("F".to_owned()); 1258 | expected.arguments.push(FunctionParameter::from("ARG1".to_owned(), TypeKind::Text)); 1259 | expected.arguments.push(FunctionParameter::from("ARG2".to_owned(), TypeKind::Number)); 1260 | 1261 | assert_eq!(got_func, expected); 1262 | } 1263 | } 1264 | 1265 | #[test] 1266 | fn numeric_tokens() { 1267 | use parser::*; 1268 | 1269 | { 1270 | let src = "1234"; 1271 | let chars = src.chars().collect::>(); 1272 | let mut offset = 0usize; 1273 | 1274 | let tok = match next_token(&chars, &mut offset) { 1275 | Ok(t) => t, 1276 | Err(e) => panic!("{}", e), 1277 | }; 1278 | 1279 | let expected = Token::Integer(1234); 1280 | 1281 | assert_eq!(tok, expected); 1282 | } 1283 | 1284 | { 1285 | let src = "1234.567"; 1286 | let chars = src.chars().collect::>(); 1287 | let mut offset = 0usize; 1288 | 1289 | let tok = match next_token(&chars, &mut offset) { 1290 | Ok(t) => t, 1291 | Err(e) => panic!("{}", e), 1292 | }; 1293 | 1294 | let expected = Token::Number(1234.567); 1295 | 1296 | assert_eq!(tok, expected); 1297 | } 1298 | } 1299 | 1300 | #[test] 1301 | fn text_tokens() { 1302 | use parser::*; 1303 | 1304 | let src = "\"test string\""; 1305 | 1306 | let chars = src.chars().collect::>(); 1307 | 1308 | let mut offset = 0usize; 1309 | 1310 | let tok = match next_token(&chars, &mut offset) { 1311 | Ok(t) => t, 1312 | Err(e) => panic!("{}", e), 1313 | }; 1314 | 1315 | let expected = Token::Text("test string".to_owned()); 1316 | 1317 | assert_eq!(tok, expected); 1318 | } 1319 | 1320 | #[test] 1321 | fn symbols_and_keyphrases() { 1322 | use parser::*; 1323 | 1324 | { 1325 | let src = "THIS IS A SYMBOL:+()1"; 1326 | let chars = src.chars().collect::>(); 1327 | 1328 | let mut offset = 0usize; 1329 | 1330 | let tok = match next_token(&chars, &mut offset) { 1331 | Ok(t) => t, 1332 | Err(e) => panic!("{}", e) 1333 | }; 1334 | 1335 | let expected = Token::Symbol("THIS IS A SYMBOL".to_owned()); 1336 | 1337 | assert_eq!(tok, expected); 1338 | } 1339 | 1340 | { 1341 | let src = "NUM VAI DÁ NÃO"; 1342 | let chars = src.chars().collect::>(); 1343 | 1344 | let mut offset = 0usize; 1345 | 1346 | let tok = match next_token(&chars, &mut offset) { 1347 | Ok(t) => t, 1348 | Err(e) => panic!("{}", e), 1349 | }; 1350 | 1351 | let expected = Token::Command(KeyPhrase::Quit); 1352 | 1353 | assert_eq!(tok, expected); 1354 | } 1355 | } 1356 | } 1357 | -------------------------------------------------------------------------------- /birl/src/compiler.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use parser::{ Expression, ExpressionNode, FunctionParameter, Command, TypeKind, CommandArgument, MathOperator, CommandKind }; 3 | use vm::{ Instruction, ComparisionRequest }; 4 | use context::RawValue; 5 | 6 | #[derive(Debug)] 7 | enum SubScopeKind { 8 | Loop, 9 | ExecuteIf, 10 | Regular, 11 | } 12 | 13 | #[derive(Clone, Copy, PartialEq)] 14 | pub enum ScopeKind { 15 | Function, 16 | Global 17 | } 18 | 19 | #[derive(Debug, Clone)] 20 | struct SymbolEntry { 21 | address : usize, 22 | global : bool, 23 | writeable : bool, 24 | } 25 | 26 | impl SymbolEntry { 27 | fn from(address : usize, global : bool, writeable : bool) -> SymbolEntry { 28 | SymbolEntry { address, global, writeable } 29 | } 30 | } 31 | 32 | #[derive(Debug)] 33 | struct ScopeInfo { 34 | symbol_table : HashMap, 35 | scope_kind : SubScopeKind, 36 | previous_next_var_address : usize, 37 | starting_var_address : usize, 38 | } 39 | 40 | impl ScopeInfo { 41 | fn new(scope_kind : SubScopeKind, previous_next_var_address : usize, is_global : bool) -> ScopeInfo { 42 | let mut symbol_table = HashMap::new(); 43 | symbol_table.insert("TREZE".to_owned(), SymbolEntry::from(0, is_global, false)); 44 | 45 | ScopeInfo { 46 | symbol_table, 47 | scope_kind, 48 | previous_next_var_address, 49 | starting_var_address : previous_next_var_address 50 | } 51 | } 52 | } 53 | 54 | #[derive(Debug, PartialEq)] 55 | enum FunctionKind { 56 | Plugin, 57 | Source, 58 | } 59 | 60 | struct FunctionInfo { 61 | address : usize, 62 | arguments : Vec, 63 | kind : FunctionKind, 64 | } 65 | 66 | impl FunctionInfo { 67 | fn from(address : usize, arguments : Vec, kind : FunctionKind) -> FunctionInfo { 68 | FunctionInfo { address, arguments, kind } 69 | } 70 | } 71 | 72 | pub enum CompilerHint { 73 | ScopeStart, 74 | ScopeEnd, 75 | } 76 | 77 | pub struct Compiler { 78 | scopes : Vec, 79 | functions : HashMap, 80 | next_var_address : usize, 81 | current_scope : ScopeKind, 82 | } 83 | 84 | impl Compiler { 85 | pub fn new() -> Compiler { 86 | let mut funcs = HashMap::new(); 87 | funcs.insert("__global__".to_owned(), FunctionInfo::from(0, vec![], FunctionKind::Source)); 88 | funcs.insert("SHOW".to_owned(), FunctionInfo::from(1, vec![], FunctionKind::Source)); 89 | 90 | Compiler { 91 | scopes : vec![ScopeInfo::new(SubScopeKind::Regular, 1, true)], 92 | functions : funcs, 93 | next_var_address : 1, 94 | current_scope : ScopeKind::Global, 95 | } 96 | } 97 | 98 | fn get_inst_for_op(op : MathOperator) -> Option { 99 | match op { 100 | MathOperator::Plus => Some(Instruction::Add), 101 | MathOperator::Minus => Some(Instruction::Sub), 102 | MathOperator::Division => Some(Instruction::Div), 103 | MathOperator::Multiplication => Some(Instruction::Mul), 104 | _ => None, 105 | } 106 | } 107 | 108 | pub fn compile_expression(&self, expr : Expression, inst : &mut Vec) -> Result<(), String> { 109 | 110 | inst.push(Instruction::SetFirstExpressionOperation); 111 | 112 | let mut is_a = expr.nodes.len() > 1; 113 | 114 | for node in expr.nodes { 115 | match node { 116 | ExpressionNode::Operator(MathOperator::ParenthesisLeft) | 117 | ExpressionNode::Operator(MathOperator::ParenthesisRight) => unreachable!(), 118 | ExpressionNode::Operator(o) => { 119 | let opi = match Compiler::get_inst_for_op(o) { 120 | Some(i) => i, 121 | None => unreachable!(), 122 | }; 123 | 124 | inst.push(opi); 125 | 126 | is_a = true; 127 | } 128 | ExpressionNode::Value(raw) => { 129 | if is_a { 130 | inst.push(Instruction::PushValMathA(raw)); 131 | } else { 132 | inst.push(Instruction::PushValMathB(raw)); 133 | } 134 | 135 | is_a = !is_a; 136 | } 137 | ExpressionNode::Symbol(s) => { 138 | let info = match self.find_symbol(s.as_str()) { 139 | Some(i) => i, 140 | None => return Err(format!("Variável não encontrada : {}", s)), 141 | }; 142 | 143 | if info.global { 144 | inst.push(Instruction::ReadGlobalVarFrom(info.address)); 145 | } else { 146 | inst.push(Instruction::ReadVarFrom(info.address)); 147 | } 148 | 149 | if is_a { 150 | inst.push(Instruction::PushIntermediateToA); 151 | } else { 152 | inst.push(Instruction::PushIntermediateToB); 153 | } 154 | 155 | is_a = !is_a; 156 | } 157 | } 158 | } 159 | 160 | Ok(()) 161 | } 162 | 163 | fn end_scope(&mut self, info : ScopeInfo, instructions : &mut Vec) { 164 | for (_, sym) in info.symbol_table { 165 | instructions.push(Instruction::TryDecrementRefAt(sym.address)); 166 | } 167 | 168 | self.next_var_address = info.previous_next_var_address; 169 | } 170 | 171 | fn find_symbol(&self, name : &str) -> Option<&SymbolEntry> { 172 | for scope in (&self.scopes).into_iter().rev() { 173 | match scope.symbol_table.get(name) { 174 | Some(v) => return Some(v), 175 | None => {} 176 | } 177 | } 178 | 179 | None 180 | } 181 | 182 | fn add_symbol(&mut self, name : String, writeable : bool) -> Option { 183 | let is_global = self.current_scope == ScopeKind::Global; 184 | let entry = SymbolEntry::from(self.next_var_address, is_global, writeable); 185 | self.next_var_address += 1; 186 | 187 | match self.scopes.last_mut() { 188 | Some(s) => { 189 | s.symbol_table.insert(name, entry.clone()); 190 | Some(entry) 191 | } 192 | None => None, 193 | } 194 | } 195 | 196 | fn find_or_add_symbol(&mut self, name : &str, writeable : bool) -> Option { 197 | if self.scopes.is_empty() { 198 | None 199 | } else { 200 | match self.find_symbol(name) { 201 | Some(s) => return Some(s.clone()), 202 | None => {}, 203 | } 204 | 205 | match self.add_symbol(name.to_owned(), writeable) { 206 | Some(s) => Some(s), 207 | None => None, 208 | } 209 | } 210 | } 211 | 212 | fn get_function_info(&self, id : usize) -> Option<&FunctionInfo> { 213 | for (_, f) in &self.functions { 214 | if f.address == id { 215 | return Some(f); 216 | } 217 | } 218 | 219 | None 220 | } 221 | 222 | fn add_execute_while_boilerplate(&self, mut cmd : Command, instructions : &mut Vec) -> Result<(), String> { 223 | instructions.push(Instruction::AddLoopLabel); 224 | 225 | if let CommandArgument::Expression(expr) = cmd.arguments.remove(0) { 226 | self.compile_expression(expr, instructions)?; 227 | } else { 228 | return Err("Argumento 1 não é expressão".to_owned()); 229 | } 230 | 231 | // Move result to A 232 | instructions.push(Instruction::SwapMath); 233 | 234 | if let CommandArgument::Expression(expr) = cmd.arguments.remove(0) { 235 | self.compile_expression(expr, instructions)?; 236 | } else { 237 | return Err("Argumento 2 não é expressão".to_owned()); 238 | } 239 | 240 | instructions.push(Instruction::Compare); 241 | 242 | Ok(()) 243 | } 244 | 245 | pub fn compile_command(&mut self, mut cmd : Command, instructions : &mut Vec) 246 | -> Result, String> { 247 | match cmd.kind { 248 | CommandKind::PrintDebug => { 249 | // Evaluate the single argument and print-debug it 250 | 251 | if cmd.arguments.len() != 1 { 252 | return Err("Internal error : Debug print command has more than 1 argument (or less)".to_owned()); 253 | } 254 | 255 | for arg in cmd.arguments { 256 | match arg { 257 | CommandArgument::Expression(expr) => { 258 | match self.compile_expression(expr, instructions) { 259 | Ok(_) => {}, 260 | Err(e) => return Err(e), 261 | }; 262 | 263 | instructions.push(Instruction::PrintMathBDebug); 264 | } 265 | _ => return Err("Erro : Um argumento diferente de valor foi passado pra print. Erro interno.".to_owned()), 266 | } 267 | } 268 | } 269 | CommandKind::Print => { 270 | for arg in cmd.arguments { 271 | match arg { 272 | CommandArgument::Expression(expr) => { 273 | match self.compile_expression(expr, instructions) { 274 | Ok(_) => {}, 275 | Err(e) => return Err(e), 276 | }; 277 | 278 | instructions.push(Instruction::PrintMathB); 279 | } 280 | _ => return Err("Erro : Um argumento diferente de valor foi passado pra print. Erro interno.".to_owned()), 281 | } 282 | } 283 | 284 | instructions.push(Instruction::FlushStdout); 285 | } 286 | CommandKind::PrintLn => { 287 | for arg in cmd.arguments { 288 | match arg { 289 | CommandArgument::Expression(expr) => { 290 | match self.compile_expression(expr, instructions) { 291 | Ok(_) => {}, 292 | Err(e) => return Err(e), 293 | }; 294 | 295 | instructions.push(Instruction::PrintMathB); 296 | } 297 | _ => return Err("Erro : Um argumento diferente de valor foi passado pra print. Erro interno.".to_owned()), 298 | } 299 | } 300 | 301 | instructions.push(Instruction::PrintNewLine); 302 | } 303 | CommandKind::Quit => instructions.push(Instruction::Quit), 304 | CommandKind::Set => { 305 | if cmd.arguments.len() != 2 { 306 | return Err(format!("O comando BORA espera 2 argumentos, mas {} foram passados (Erro interno)", cmd.arguments.len())); 307 | } 308 | 309 | let name_arg = cmd.arguments.remove(0); 310 | 311 | let name = match name_arg { 312 | CommandArgument::Name(n) => n, 313 | _ => return Err(format!("Erro interno : Esperado um nome pro BORA, encontrado {:?}", name_arg)), 314 | }; 315 | 316 | let entry = match self.find_symbol(name.as_str()) { 317 | Some(e) => e, 318 | None => return Err(format!("Variável {} não encontrada", name)) 319 | }; 320 | 321 | if ! entry.writeable { 322 | return Err(format!("Erro : A variável {} não pode ser escrita", name)); 323 | } 324 | 325 | let expr_arg = cmd.arguments.remove(0); 326 | 327 | match expr_arg { 328 | CommandArgument::Expression(expr) => { 329 | match self.compile_expression(expr, instructions) { 330 | Ok(_) => {} 331 | Err(e) => return Err(e) 332 | } 333 | } 334 | _ => return Err(format!("Erro interno : Esperado uma expressão depois do nome, encontrado {:?}", expr_arg)), 335 | } 336 | 337 | let inst = if entry.global { 338 | Instruction::WriteGlobalVarTo(entry.address) 339 | } else { 340 | Instruction::WriteVarTo(entry.address) 341 | }; 342 | 343 | instructions.push(inst); 344 | } 345 | CommandKind::Declare => { 346 | let name_arg = cmd.arguments.remove(0); 347 | 348 | let name = match name_arg { 349 | CommandArgument::Name(n) => n, 350 | _ => return Err(format!("Erro interno : Esperado um nome pro BORA, encontrado {:?}", name_arg)), 351 | }; 352 | 353 | let is_global = self.current_scope == ScopeKind::Global; 354 | 355 | if cmd.arguments.is_empty() { 356 | // Set value to Null 357 | // To achieve this, we set both Maths to null, then copy B to the var address 358 | 359 | instructions.push(Instruction::ClearMath); 360 | } else { 361 | let expr_arg = cmd.arguments.remove(0); 362 | 363 | match expr_arg { 364 | CommandArgument::Expression(expr) => { 365 | match self.compile_expression(expr, instructions) { 366 | Ok(_) => {} 367 | Err(e) => return Err(e) 368 | } 369 | } 370 | _ => return Err(format!("Erro interno : Esperado uma expressão depois do nome, encontrado {:?}", expr_arg)), 371 | } 372 | } 373 | 374 | // Add the variable after the expression is parsed, so we can't use the variable before a value is set 375 | 376 | let address = self.next_var_address; 377 | self.next_var_address += 1; 378 | 379 | match self.scopes.last_mut() { 380 | Some(s) => s.symbol_table.insert(name, SymbolEntry::from(address, is_global, true)), 381 | None => return Err(format!("Scopes é vazio")) 382 | }; 383 | 384 | if is_global { 385 | instructions.push(Instruction::WriteGlobalVarTo(address)); 386 | } else { 387 | instructions.push(Instruction::WriteVarTo(address)); 388 | } 389 | } 390 | CommandKind::Return => { 391 | if cmd.arguments.is_empty() { 392 | instructions.push(Instruction::ClearMath); 393 | } else { 394 | let expr_arg = cmd.arguments.remove(0); 395 | 396 | match expr_arg { 397 | CommandArgument::Expression(expr) => { 398 | match self.compile_expression(expr, instructions) { 399 | Ok(_) => {} 400 | Err(e) => return Err(e) 401 | } 402 | } 403 | _ => return Err(format!("Esperado uma expressão como argumento pro comando Return, encontrado {:?}", expr_arg)), 404 | } 405 | } 406 | 407 | instructions.push(Instruction::Return); 408 | } 409 | CommandKind::Compare => { 410 | let left_expr_arg = cmd.arguments.remove(0); 411 | 412 | match left_expr_arg { 413 | CommandArgument::Expression(expr) => { 414 | match self.compile_expression(expr, instructions) { 415 | Ok(_) => {} 416 | Err(e) => return Err(e) 417 | } 418 | } 419 | _ => return Err(format!("Esperado uma expressão como argumento pro comando Return, encontrado {:?}", left_expr_arg)), 420 | } 421 | 422 | instructions.push(Instruction::SwapMath); 423 | 424 | let right_expr_arg = cmd.arguments.remove(0); 425 | 426 | match right_expr_arg { 427 | CommandArgument::Expression(expr) => { 428 | match self.compile_expression(expr, instructions) { 429 | Ok(_) => {} 430 | Err(e) => return Err(e) 431 | } 432 | } 433 | _ => return Err(format!("Esperado uma expressão como argumento pro comando Return, encontrado {:?}", right_expr_arg)), 434 | } 435 | 436 | instructions.push(Instruction::Compare); 437 | } 438 | CommandKind::EndSubScope => { 439 | let scope_info = match self.scopes.pop() { 440 | Some(s) => s, 441 | None => return Err(format!("FIM fora de qualquer scope")) 442 | }; 443 | 444 | match scope_info.scope_kind { 445 | SubScopeKind::ExecuteIf => instructions.push(Instruction::EndConditionalBlock), 446 | SubScopeKind::Loop => { 447 | instructions.push(Instruction::RestoreLoopLabel); 448 | instructions.push(Instruction::EndConditionalBlock); 449 | instructions.push(Instruction::PopLoopLabel); 450 | } 451 | SubScopeKind::Regular => { 452 | self.scopes.push(scope_info); 453 | 454 | return Err("Erro : Usando FIM pra finalizar uma função".to_owned()); 455 | } 456 | } 457 | 458 | self.end_scope(scope_info, instructions); 459 | 460 | return Ok(Some(CompilerHint::ScopeEnd)); 461 | }, 462 | CommandKind::ExecuteIfEqual => { 463 | let is_global = self.current_scope == ScopeKind::Global; 464 | self.scopes.push(ScopeInfo::new(SubScopeKind::ExecuteIf, 465 | self.next_var_address, is_global)); 466 | instructions.push(Instruction::ExecuteIf(ComparisionRequest::Equal)); 467 | 468 | return Ok(Some(CompilerHint::ScopeStart)); 469 | }, 470 | CommandKind::ExecuteIfNotEqual => { 471 | let is_global = self.current_scope == ScopeKind::Global; 472 | self.scopes.push(ScopeInfo::new(SubScopeKind::ExecuteIf, 473 | self.next_var_address, is_global)); 474 | instructions.push(Instruction::ExecuteIf(ComparisionRequest::NotEqual)); 475 | 476 | return Ok(Some(CompilerHint::ScopeStart)); 477 | }, 478 | CommandKind::ExecuteIfEqualOrGreater => { 479 | let is_global = self.current_scope == ScopeKind::Global; 480 | self.scopes.push(ScopeInfo::new(SubScopeKind::ExecuteIf, 481 | self.next_var_address, is_global)); 482 | instructions.push(Instruction::ExecuteIf(ComparisionRequest::MoreOrEqual)); 483 | 484 | return Ok(Some(CompilerHint::ScopeStart)); 485 | }, 486 | CommandKind::ExecuteIfGreater => { 487 | let is_global = self.current_scope == ScopeKind::Global; 488 | self.scopes.push(ScopeInfo::new(SubScopeKind::ExecuteIf, 489 | self.next_var_address, is_global)); 490 | instructions.push(Instruction::ExecuteIf(ComparisionRequest::More)); 491 | 492 | return Ok(Some(CompilerHint::ScopeStart)); 493 | }, 494 | CommandKind::ExecuteIfEqualOrLess => { 495 | let is_global = self.current_scope == ScopeKind::Global; 496 | self.scopes.push(ScopeInfo::new(SubScopeKind::ExecuteIf, 497 | self.next_var_address, is_global)); 498 | instructions.push(Instruction::ExecuteIf(ComparisionRequest::LessOrEqual)); 499 | 500 | return Ok(Some(CompilerHint::ScopeStart)); 501 | }, 502 | CommandKind::ExecuteIfLess => { 503 | let is_global = self.current_scope == ScopeKind::Global; 504 | self.scopes.push(ScopeInfo::new(SubScopeKind::ExecuteIf, 505 | self.next_var_address, is_global)); 506 | instructions.push(Instruction::ExecuteIf(ComparisionRequest::Less)); 507 | 508 | return Ok(Some(CompilerHint::ScopeStart)); 509 | }, 510 | CommandKind::Call => { 511 | // First argument is the function name 512 | 513 | let info = if let CommandArgument::Name(name) = cmd.arguments.remove(0) { 514 | match self.functions.get(name.as_str()) { 515 | Some(i) => i, 516 | None => return Err(format!("Função {} não encontrada", name)) 517 | } 518 | } else { 519 | return Err("É HORA DO espera um nome pra função".to_owned()); 520 | }; 521 | 522 | if info.kind == FunctionKind::Source { 523 | instructions.push(Instruction::MakeNewFrame(info.address)); 524 | } 525 | 526 | let mut index = 0usize; 527 | let num_args = cmd.arguments.len(); 528 | 529 | for arg in cmd.arguments { 530 | let expr = match arg { 531 | CommandArgument::Expression(e) => e, 532 | _ => return Err("Erro interno : Era esperado um valor como argumento \ 533 | pro comando.".to_owned()), 534 | }; 535 | 536 | let expected_type = info.arguments[index]; 537 | 538 | // The parameter address is, in this case, index + 1 (because the address 0 is reserved to 539 | // the return value) 540 | 541 | match self.compile_expression(expr, instructions) { 542 | Ok(_) => {} 543 | Err(e) => return Err(e) 544 | }; 545 | 546 | instructions.push(Instruction::AssertMathBCompatible(expected_type)); 547 | 548 | if info.kind == FunctionKind::Source { 549 | instructions.push(Instruction::WriteVarToLast(index + 1)); 550 | } else { 551 | instructions.push(Instruction::PushMathBPluginArgument); 552 | } 553 | 554 | index += 1; 555 | } 556 | 557 | if info.kind == FunctionKind::Source { 558 | instructions.push(Instruction::SetLastFrameReady); 559 | } else if info.kind == FunctionKind::Plugin { 560 | instructions.push(Instruction::CallPlugin(info.address, num_args)); 561 | } 562 | } 563 | CommandKind::GetStringInput => { 564 | let name_arg = cmd.arguments.remove(0); 565 | 566 | let name = match name_arg { 567 | CommandArgument::Name(s) => s, 568 | _ => return Err("Erro interno : Esperado um nome pra GetInput*".to_owned()), 569 | }; 570 | 571 | let entry = match self.find_or_add_symbol(name.as_str(), true) { 572 | Some(e) => e, 573 | None => return Err(format!("Variável {} não encontrada", name)) 574 | }; 575 | 576 | instructions.push(Instruction::ReadInput); 577 | instructions.push(Instruction::PushIntermediateToB); 578 | 579 | if entry.global { 580 | instructions.push(Instruction::WriteGlobalVarTo(entry.address)); 581 | } else { 582 | instructions.push(Instruction::WriteVarTo(entry.address)); 583 | } 584 | } 585 | CommandKind::GetIntegerInput => { 586 | let name_arg = cmd.arguments.remove(0); 587 | 588 | let name = match name_arg { 589 | CommandArgument::Name(s) => s, 590 | _ => return Err("Erro interno : Esperado um nome pra GetInput*".to_owned()), 591 | }; 592 | 593 | let entry = match self.find_or_add_symbol(name.as_str(), true) { 594 | Some(e) => e, 595 | None => return Err(format!("Variável {} não encontrada", name)) 596 | }; 597 | 598 | instructions.push(Instruction::ReadInput); 599 | 600 | instructions.push(Instruction::PushIntermediateToB); 601 | 602 | instructions.push(Instruction::ConvertToInt); 603 | 604 | if entry.global { 605 | instructions.push(Instruction::WriteGlobalVarTo(entry.address)); 606 | } else { 607 | instructions.push(Instruction::WriteVarTo(entry.address)); 608 | } 609 | } 610 | CommandKind::GetNumberInput => { 611 | let name_arg = cmd.arguments.remove(0); 612 | 613 | let name = match name_arg { 614 | CommandArgument::Name(s) => s, 615 | _ => return Err("Erro interno : Esperado um nome pra GetInput*".to_owned()), 616 | }; 617 | 618 | let entry = match self.find_or_add_symbol(name.as_str(), true) { 619 | Some(e) => e, 620 | None => return Err(format!("Variável {} não encontrada", name)) 621 | }; 622 | 623 | instructions.push(Instruction::ReadInput); 624 | 625 | instructions.push(Instruction::PushIntermediateToB); 626 | 627 | instructions.push(Instruction::ConvertToNum); 628 | 629 | if entry.global { 630 | instructions.push(Instruction::WriteGlobalVarTo(entry.address)); 631 | } else { 632 | instructions.push(Instruction::WriteVarTo(entry.address)); 633 | } 634 | } 635 | CommandKind::ConvertToInt => { 636 | let name_arg = cmd.arguments.remove(0); 637 | 638 | let name = match name_arg { 639 | CommandArgument::Name(s) => s, 640 | _ => return Err("Erro interno : Esperado um nome pra GetInput*".to_owned()), 641 | }; 642 | 643 | let entry = match self.find_symbol(name.as_str()) { 644 | Some(e) => e, 645 | None => return Err(format!("Variável {} não encontrada", name)) 646 | }; 647 | 648 | if entry.global { 649 | instructions.push(Instruction::ReadGlobalVarFrom(entry.address)); 650 | } else { 651 | instructions.push(Instruction::ReadVarFrom(entry.address)); 652 | } 653 | 654 | instructions.push(Instruction::PushIntermediateToB); 655 | 656 | instructions.push(Instruction::ConvertToInt); 657 | 658 | if entry.global { 659 | instructions.push(Instruction::WriteGlobalVarTo(entry.address)); 660 | } else { 661 | instructions.push(Instruction::WriteVarTo(entry.address)); 662 | } 663 | } 664 | CommandKind::ConvertToNum => { 665 | let name_arg = cmd.arguments.remove(0); 666 | 667 | let name = match name_arg { 668 | CommandArgument::Name(s) => s, 669 | _ => return Err("Erro interno : Esperado um nome pra GetInput*".to_owned()), 670 | }; 671 | 672 | let entry = match self.find_symbol(name.as_str()) { 673 | Some(e) => e, 674 | None => return Err(format!("Variável {} não encontrada", name)) 675 | }; 676 | 677 | if entry.global { 678 | instructions.push(Instruction::ReadGlobalVarFrom(entry.address)); 679 | } else { 680 | instructions.push(Instruction::ReadVarFrom(entry.address)); 681 | } 682 | 683 | instructions.push(Instruction::PushIntermediateToB); 684 | 685 | instructions.push(Instruction::ConvertToNum); 686 | 687 | if entry.global { 688 | instructions.push(Instruction::WriteGlobalVarTo(entry.address)); 689 | } else { 690 | instructions.push(Instruction::WriteVarTo(entry.address)); 691 | } 692 | } 693 | CommandKind::IntoString => { 694 | let name_arg = cmd.arguments.remove(0); 695 | 696 | let name = match name_arg { 697 | CommandArgument::Name(s) => s, 698 | _ => return Err("Erro interno : Esperado um nome pra GetInput*".to_owned()), 699 | }; 700 | 701 | let entry = match self.find_symbol(name.as_str()) { 702 | Some(e) => e, 703 | None => return Err(format!("Variável {} não encontrada", name)) 704 | }; 705 | 706 | if entry.global { 707 | instructions.push(Instruction::ReadGlobalVarFrom(entry.address)); 708 | } else { 709 | instructions.push(Instruction::ReadVarFrom(entry.address)); 710 | } 711 | 712 | instructions.push(Instruction::PushIntermediateToB); 713 | 714 | instructions.push(Instruction::ConvertToString); 715 | 716 | if entry.global { 717 | instructions.push(Instruction::WriteGlobalVarTo(entry.address)); 718 | } else { 719 | instructions.push(Instruction::WriteVarTo(entry.address)); 720 | } 721 | } 722 | CommandKind::ExecuteWhileEqual => { 723 | let is_global = self.current_scope == ScopeKind::Global; 724 | self.scopes.push(ScopeInfo::new(SubScopeKind::Loop, self.next_var_address, is_global)); 725 | 726 | self.add_execute_while_boilerplate(cmd, instructions)?; 727 | 728 | instructions.push(Instruction::ExecuteIf(ComparisionRequest::Equal)); 729 | return Ok(Some(CompilerHint::ScopeStart)); 730 | } 731 | CommandKind::ExecuteWhileNotEqual => { 732 | let is_global = self.current_scope == ScopeKind::Global; 733 | self.scopes.push(ScopeInfo::new(SubScopeKind::Loop, self.next_var_address, is_global)); 734 | 735 | self.add_execute_while_boilerplate(cmd, instructions)?; 736 | 737 | instructions.push(Instruction::ExecuteIf(ComparisionRequest::NotEqual)); 738 | return Ok(Some(CompilerHint::ScopeStart)); 739 | } 740 | CommandKind::ExecuteWhileGreater => { 741 | let is_global = self.current_scope == ScopeKind::Global; 742 | self.scopes.push(ScopeInfo::new(SubScopeKind::Loop, self.next_var_address, is_global)); 743 | 744 | self.add_execute_while_boilerplate(cmd, instructions)?; 745 | 746 | instructions.push(Instruction::ExecuteIf(ComparisionRequest::More)); 747 | return Ok(Some(CompilerHint::ScopeStart)); 748 | } 749 | CommandKind::ExecuteWhileEqualOrGreater => { 750 | let is_global = self.current_scope == ScopeKind::Global; 751 | self.scopes.push(ScopeInfo::new(SubScopeKind::Loop, self.next_var_address, is_global)); 752 | 753 | self.add_execute_while_boilerplate(cmd, instructions)?; 754 | 755 | instructions.push(Instruction::ExecuteIf(ComparisionRequest::MoreOrEqual)); 756 | return Ok(Some(CompilerHint::ScopeStart)); 757 | } 758 | CommandKind::ExecuteWhileLess => { 759 | let is_global = self.current_scope == ScopeKind::Global; 760 | self.scopes.push(ScopeInfo::new(SubScopeKind::Loop, self.next_var_address, is_global)); 761 | 762 | self.add_execute_while_boilerplate(cmd, instructions)?; 763 | 764 | instructions.push(Instruction::ExecuteIf(ComparisionRequest::Less)); 765 | return Ok(Some(CompilerHint::ScopeStart)); 766 | } 767 | CommandKind::ExecuteWhileEqualOrLess => { 768 | let is_global = self.current_scope == ScopeKind::Global; 769 | self.scopes.push(ScopeInfo::new(SubScopeKind::Loop, self.next_var_address, is_global)); 770 | 771 | self.add_execute_while_boilerplate(cmd, instructions)?; 772 | 773 | instructions.push(Instruction::ExecuteIf(ComparisionRequest::LessOrEqual)); 774 | return Ok(Some(CompilerHint::ScopeStart)); 775 | } 776 | CommandKind::RangeLoop => { 777 | let is_global = self.current_scope == ScopeKind::Global; 778 | self.scopes.push(ScopeInfo::new(SubScopeKind::Loop, self.next_var_address, is_global)); 779 | 780 | let name = if let CommandArgument::Name(n) = cmd.arguments.remove(0) { 781 | n 782 | } else { 783 | return Err("Esperado uma variável pro primeiro argumento do loop".to_owned()); 784 | }; 785 | 786 | let entry = match self.find_or_add_symbol(name.as_str(), true) { 787 | Some(e) => e, 788 | None => return Err(format!("Não foi possível adicionar nem encontrar a variável {}", name)), 789 | }; 790 | 791 | // Initialize counter 792 | 793 | if let CommandArgument::Expression(expr) = cmd.arguments.remove(0) { 794 | self.compile_expression(expr, instructions)?; 795 | 796 | if entry.global { 797 | instructions.push(Instruction::WriteGlobalVarTo(entry.address)); 798 | } else { 799 | instructions.push(Instruction::WriteVarTo(entry.address)); 800 | } 801 | } else { 802 | return Err("Era esperado uma expressão pro segundo argumento de RangedLoop".to_owned()); 803 | } 804 | 805 | let final_expr = if let CommandArgument::Expression(expr) = cmd.arguments.remove(0) { 806 | expr 807 | } else { 808 | return Err("Esperado um valor final".to_owned()); 809 | }; 810 | 811 | // Register increment procedure 812 | 813 | if cmd.arguments.is_empty() { 814 | instructions.push(Instruction::PushValMathB(RawValue::Integer(1))); 815 | } else { 816 | if let CommandArgument::Expression(step_expr) = cmd.arguments.remove(0) { 817 | self.compile_expression(step_expr, instructions)?; 818 | } else { 819 | instructions.push(Instruction::PushValMathB(RawValue::Integer(1))); 820 | } 821 | } 822 | 823 | // Loop starts here 824 | 825 | instructions.push(Instruction::AddLoopLabel); 826 | 827 | instructions.push(Instruction::RegisterIncrementOnRestore(entry.address)); 828 | 829 | // Check if should continue 830 | 831 | self.compile_expression(final_expr, instructions)?; 832 | 833 | if entry.global { 834 | instructions.push(Instruction::ReadGlobalVarFrom(entry.address)); 835 | } else { 836 | instructions.push(Instruction::ReadVarFrom(entry.address)); 837 | } 838 | 839 | instructions.push(Instruction::PushIntermediateToA); 840 | 841 | instructions.push(Instruction::Compare); 842 | 843 | instructions.push(Instruction::ExecuteIf(ComparisionRequest::NotEqual)); 844 | 845 | return Ok(Some(CompilerHint::ScopeStart)); 846 | } 847 | CommandKind::MakeNewList => { 848 | let name = if let CommandArgument::Name(name) = cmd.arguments.remove(0) { 849 | name 850 | } else { 851 | return Err("MakeNewList : Esperado um nome".to_owned()); 852 | }; 853 | 854 | let entry = match self.find_or_add_symbol(name.as_str(), true) { 855 | Some(a) => a, 856 | None => return Err(format!("Não foi possível declarar a variável pra lista {}", name)) 857 | }; 858 | 859 | instructions.push(Instruction::MakeNewList); 860 | 861 | if entry.global { 862 | instructions.push(Instruction::WriteGlobalVarTo(entry.address)); 863 | } else { 864 | instructions.push(Instruction::WriteVarTo(entry.address)); 865 | } 866 | } 867 | CommandKind::QueryListSize => { 868 | let list_name = if let CommandArgument::Name(name) = cmd.arguments.remove(0) { 869 | name 870 | } else { 871 | return Err("MakeNewList : Esperado um nome".to_owned()); 872 | }; 873 | 874 | let dest_name = if let CommandArgument::Name(name) = cmd.arguments.remove(0) { 875 | name 876 | } else { 877 | return Err("MakeNewList : Esperado um nome".to_owned()); 878 | }; 879 | 880 | let dest = match self.find_or_add_symbol(dest_name.as_str(), true) { 881 | Some(d) => d, 882 | None => return Err(format!("Não foi possível declarar a variável pra lista {}", dest_name)) 883 | }; 884 | 885 | let list = match self.find_symbol(list_name.as_str()) { 886 | Some(a) => a, 887 | None => return Err(format!("Não foi possível encontrar a lista {}", list_name)) 888 | }; 889 | 890 | if list.global { 891 | instructions.push(Instruction::ReadGlobalVarFrom(list.address)); 892 | } else { 893 | instructions.push(Instruction::ReadVarFrom(list.address)); 894 | } 895 | 896 | instructions.push(Instruction::QueryListSize); 897 | 898 | if dest.global { 899 | instructions.push(Instruction::WriteGlobalVarTo(dest.address)); 900 | } else { 901 | instructions.push(Instruction::WriteVarTo(dest.address)); 902 | } 903 | } 904 | CommandKind::AddListElement => { 905 | let list_name = if let CommandArgument::Name(name) = cmd.arguments.remove(0) { 906 | name 907 | } else { 908 | return Err("AddListElement : Esperado um nome".to_owned()) 909 | }; 910 | 911 | let element = if let CommandArgument::Expression(expr) = cmd.arguments.remove(0) { 912 | expr 913 | } else { 914 | return Err("AddListElement : Esperado um elemento".to_owned()) 915 | }; 916 | 917 | let index = if cmd.arguments.is_empty() { 918 | None 919 | } else { 920 | if let CommandArgument::Expression(expr) = cmd.arguments.remove(0) { 921 | Some(expr) 922 | } else { 923 | return Err("AddListElement : Era esperado uma expressão como um index".to_owned()); 924 | } 925 | }; 926 | 927 | let list = match self.find_symbol(list_name.as_str()) { 928 | Some(l) => l, 929 | None => return Err(format!("Não foi possível encontrar a lista {}", list_name)) 930 | }; 931 | 932 | if list.global { 933 | instructions.push(Instruction::ReadGlobalVarFrom(list.address)); 934 | } else { 935 | instructions.push(Instruction::ReadVarFrom(list.address)); 936 | } 937 | 938 | if let Some(expr) = index { 939 | self.compile_expression(expr, instructions)?; 940 | 941 | instructions.push(Instruction::PushMathBToSeconday); 942 | } else { 943 | instructions.push(Instruction::ClearSecondary); 944 | } 945 | 946 | self.compile_expression(element, instructions)?; 947 | 948 | instructions.push(Instruction::AddToListAtIndex); 949 | } 950 | CommandKind::RemoveListElement => { 951 | let name = if let CommandArgument::Name(name) = cmd.arguments.remove(0) { 952 | name 953 | } else { 954 | return Err("RemoveListElement : Esperado um nome".to_owned()) 955 | }; 956 | 957 | let index = if let CommandArgument::Expression(expr) = cmd.arguments.remove(0) { 958 | expr 959 | } else { 960 | return Err("RemoveListElement : Esperado uma expressão".to_owned()) 961 | }; 962 | 963 | let list = match self.find_symbol(name.as_str()) { 964 | Some(e) => e, 965 | None => return Err(format!("Variável {} não encontrada", name)) 966 | }; 967 | 968 | if list.global { 969 | instructions.push(Instruction::ReadGlobalVarFrom(list.address)); 970 | } else { 971 | instructions.push(Instruction::ReadVarFrom(list.address)); 972 | } 973 | 974 | self.compile_expression(index, instructions)?; 975 | 976 | instructions.push(Instruction::RemoveFromListAtIndex); 977 | } 978 | CommandKind::IndexList => { 979 | let name = if let CommandArgument::Name(name) = cmd.arguments.remove(0) { 980 | name 981 | } else { 982 | return Err("IndexList : Esperado um nome".to_owned()) 983 | }; 984 | 985 | let index = if let CommandArgument::Expression(expr) = cmd.arguments.remove(0) { 986 | expr 987 | } else { 988 | return Err("IndexList : Esperado uma expressão".to_owned()) 989 | }; 990 | 991 | let dest_name = if let CommandArgument::Name(name) = cmd.arguments.remove(0) { 992 | name 993 | } else { 994 | return Err("IndexList : Esperado um nome".to_owned()) 995 | }; 996 | 997 | let dest = match self.find_or_add_symbol(dest_name.as_str(), true) { 998 | Some(e) => e, 999 | None => return Err(format!("Não foi possível encontrar ou declarar a variável {}", dest_name)) 1000 | }; 1001 | 1002 | let list = match self.find_symbol(name.as_str()) { 1003 | Some(e) => e, 1004 | None => return Err(format!("Variável {} não encontrada", name)) 1005 | }; 1006 | 1007 | if list.global { 1008 | instructions.push(Instruction::ReadGlobalVarFrom(list.address)); 1009 | } else { 1010 | instructions.push(Instruction::ReadVarFrom(list.address)); 1011 | } 1012 | 1013 | self.compile_expression(index, instructions)?; 1014 | 1015 | instructions.push(Instruction::IndexList); 1016 | 1017 | if dest.global { 1018 | instructions.push(Instruction::WriteGlobalVarTo(dest.address)); 1019 | } else { 1020 | instructions.push(Instruction::WriteVarTo(dest.address)); 1021 | } 1022 | } 1023 | CommandKind::BreakScope => { 1024 | instructions.push(Instruction::IncreaseSkippingLevel); 1025 | } 1026 | CommandKind::SkipNextIteration => { 1027 | instructions.push(Instruction::RestoreLoopLabel); 1028 | } 1029 | } 1030 | 1031 | Ok(None) 1032 | } 1033 | 1034 | pub fn begin_compiling_function(&mut self, address : usize, args : Vec, name : String) -> Result<(), String> { 1035 | let mut base_scope = ScopeInfo::new(SubScopeKind::Regular, 1036 | self.next_var_address, false); 1037 | 1038 | self.next_var_address = 1; 1039 | 1040 | let mut args_kind = vec![]; 1041 | 1042 | for arg in args { 1043 | args_kind.push(arg.kind); 1044 | 1045 | base_scope.symbol_table.insert(arg.name, SymbolEntry::from(self.next_var_address, false, true)); 1046 | self.next_var_address += 1; 1047 | } 1048 | 1049 | self.current_scope = ScopeKind::Function; 1050 | self.functions.insert(name, FunctionInfo::from(address, args_kind, FunctionKind::Source)); 1051 | self.scopes.push(base_scope); 1052 | 1053 | Ok(()) 1054 | } 1055 | 1056 | pub fn add_plugin_function_definition(&mut self, address : usize, params : Vec, name : String) -> Result<(), String> { 1057 | let info = FunctionInfo::from(address, params, FunctionKind::Plugin); 1058 | 1059 | match self.functions.insert(name, info) { 1060 | None => Ok(()), 1061 | Some(_) => Err(format!("Erro adicionando plugin : Função já existe")) 1062 | } 1063 | } 1064 | 1065 | pub fn compile_global_variable(&mut self, name : String, value : RawValue, writeable : bool, instructions : &mut Vec) -> Result<(), String> { 1066 | if self.current_scope != ScopeKind::Global { 1067 | return Err("Scope atual não é o global".to_owned()); 1068 | } 1069 | 1070 | let entry = match self.add_symbol(name, writeable) { 1071 | Some(e) => e, 1072 | None => return Err("Não foi possível adicionar o símbolo".to_owned()) 1073 | }; 1074 | 1075 | instructions.push(Instruction::PushValMathB(value)); 1076 | instructions.push(Instruction::WriteGlobalVarTo(entry.address)); 1077 | 1078 | Ok(()) 1079 | } 1080 | 1081 | pub fn compile_function_call(&self, id : usize, args : Vec, instructions : &mut Vec) 1082 | -> Result<(), String> 1083 | { 1084 | let info = match self.get_function_info(id) { 1085 | Some(i) => i, 1086 | None => return Err(format!("Não encontrada função com id {}", id)) 1087 | }; 1088 | 1089 | if info.arguments.len() != args.len() { 1090 | return Err(format!("CompileFunctionCall : A função com ID {} espera {} argumentos, mas {} foram passados.", id, 1091 | info.arguments.len(), args.len())); 1092 | } 1093 | 1094 | instructions.push(Instruction::MakeNewFrame(id)); 1095 | 1096 | let mut index = 0usize; 1097 | 1098 | for arg in args { 1099 | let expected = info.arguments[index]; 1100 | 1101 | match &arg { 1102 | &RawValue::Integer(_) => { 1103 | if expected != TypeKind::Integer && expected != TypeKind::Number { 1104 | return Err(format!("Tipo incompatível : Função espera {:?}, foi passado Inteiro", expected)) 1105 | } 1106 | } 1107 | &RawValue::Number(_) => { 1108 | if expected != TypeKind::Number { 1109 | return Err(format!("Tipo incompatível : Função espera {:?}, foi passado Número", expected)) 1110 | } 1111 | } 1112 | &RawValue::Text(_) => { 1113 | if expected != TypeKind::Text { 1114 | return Err(format!("Tipo incompatível : Função espera {:?}, foi passado Texto", expected)) 1115 | } 1116 | } 1117 | &RawValue::Null => { 1118 | return Err(format!("Tipo incompatível : Passado Nulo como argumento")) 1119 | } 1120 | } 1121 | 1122 | index += 1; 1123 | 1124 | instructions.push(Instruction::PushValMathB(arg)); 1125 | Instruction::WriteVarToLast(index + 1); 1126 | } 1127 | 1128 | instructions.push(Instruction::SetLastFrameReady); 1129 | 1130 | Ok(()) 1131 | } 1132 | 1133 | pub fn end_compiling_function(&mut self, instructions : &mut Vec) -> Result<(), String> { 1134 | // Push a return if the last instruction is not a return 1135 | match instructions.last() { 1136 | Some(Instruction::Return) | None => {} 1137 | Some(_) => instructions.push(Instruction::Return) 1138 | }; 1139 | 1140 | match self.scopes.pop() { 1141 | Some(s) => { 1142 | match s.scope_kind { 1143 | SubScopeKind::Regular => {} 1144 | _ => return Err("Fim da função encontrado, mas algum scope foi deixado aberto".to_owned()), 1145 | } 1146 | 1147 | self.end_scope(s, instructions); 1148 | 1149 | self.current_scope = ScopeKind::Global; 1150 | 1151 | Ok(()) 1152 | } 1153 | None => Err("".to_owned()) 1154 | } 1155 | } 1156 | } 1157 | -------------------------------------------------------------------------------- /birl/src/vm.rs: -------------------------------------------------------------------------------- 1 | use parser::{ TypeKind, IntegerType }; 2 | use context::RawValue; 3 | 4 | use std::io::{ Write, BufRead }; 5 | use std::fmt::{ Display, self }; 6 | 7 | const STACK_DEFAULT_SIZE : usize = 128; 8 | 9 | pub type PluginFunction = fn (arguments : Vec, vm : &mut VirtualMachine) -> Result, String>; 10 | 11 | #[derive(Debug, Clone, Copy, PartialEq)] 12 | pub enum Comparision { 13 | Equal, 14 | NotEqual, 15 | LessThan, 16 | MoreThan, 17 | } 18 | 19 | #[derive(Debug, Clone, Copy)] 20 | pub enum ComparisionRequest { 21 | Equal, 22 | NotEqual, 23 | Less, LessOrEqual, 24 | More, MoreOrEqual, 25 | } 26 | 27 | impl Display for Comparision { 28 | fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result { 29 | match self { 30 | Comparision::Equal => write!(f, "Igual"), 31 | Comparision::NotEqual => write!(f, "Diferente"), 32 | Comparision::LessThan => write!(f, "Menor"), 33 | Comparision::MoreThan => write!(f, "Maior"), 34 | } 35 | } 36 | } 37 | 38 | #[derive(Debug, Clone, Copy)] 39 | pub enum DynamicValue { 40 | Integer(IntegerType), 41 | Number(f64), 42 | Text(u64), 43 | List(u64), 44 | Null, 45 | } 46 | 47 | #[derive(Debug)] 48 | pub enum SpecialItemData { 49 | Text(String), 50 | List(Vec>) 51 | } 52 | 53 | impl SpecialItemData { 54 | pub fn try_into_str(&self) -> Option<&str> { 55 | match self { 56 | &SpecialItemData::Text(ref s) => Some(s.as_str()), 57 | _ => None 58 | } 59 | } 60 | 61 | pub fn try_into_str_mut(&mut self) -> Option<&mut String> { 62 | match self { 63 | &mut SpecialItemData::Text(ref mut s) => Some(s), 64 | _ => None 65 | } 66 | } 67 | 68 | pub fn try_into_list(&self) -> Option<&Vec>> { 69 | match self { 70 | &SpecialItemData::List(ref l) => Some(l), 71 | _ => None 72 | } 73 | } 74 | 75 | pub fn try_into_list_mut(&mut self) -> Option<&mut Vec>> { 76 | match self { 77 | &mut SpecialItemData::List(ref mut l) => Some(l), 78 | _ => None 79 | } 80 | } 81 | } 82 | 83 | #[derive(Debug)] 84 | pub struct SpecialItem { 85 | data : SpecialItemData, 86 | item_id : u64, 87 | ref_count : u64, 88 | } 89 | 90 | #[derive(Debug)] 91 | pub struct SpecialStorage { 92 | items : Vec, 93 | next_item_id : u64, 94 | } 95 | 96 | impl SpecialStorage { 97 | fn new() -> SpecialStorage { 98 | SpecialStorage { 99 | items : vec![], 100 | next_item_id : 0, 101 | } 102 | } 103 | 104 | pub fn add(&mut self, data : SpecialItemData, ref_count : u64) -> u64 { 105 | let item_id = self.next_item_id; 106 | self.next_item_id += 1; 107 | 108 | let item = SpecialItem { 109 | data, 110 | item_id, 111 | ref_count 112 | }; 113 | 114 | self.items.push(item); 115 | 116 | item_id 117 | } 118 | 119 | pub fn decrement_ref(&mut self, id : u64) -> Result<(), String> 120 | { 121 | for i in 0..self.items.len() { 122 | if self.items[i].item_id == id { 123 | if self.items[i].ref_count <= 1 { 124 | self.items.remove(i); 125 | } else { 126 | self.items[i].ref_count -= 1; 127 | } 128 | 129 | break; 130 | } 131 | } 132 | 133 | Ok(()) 134 | } 135 | 136 | pub fn increment_ref(&mut self, id : u64) -> Result<(), String> 137 | { 138 | match self.get_mut(id) { 139 | Some(item) => item.ref_count += 1, 140 | None => return Err("Invalid item ID".to_owned()) 141 | }; 142 | 143 | Ok(()) 144 | } 145 | 146 | pub fn get_data_ref(&self, id : u64) -> Option<&SpecialItemData> { 147 | Some(&self.get_ref(id)?.data) 148 | } 149 | 150 | pub fn get_data_mut(&mut self, id : u64) -> Option<&mut SpecialItemData> { 151 | Some(&mut self.get_mut(id)?.data) 152 | } 153 | 154 | pub fn get_ref(&self, id : u64) -> Option<&SpecialItem> { 155 | for e in &self.items { 156 | if e.item_id == id { 157 | return Some(e); 158 | } 159 | } 160 | 161 | None 162 | } 163 | 164 | pub fn get_mut(&mut self, id : u64) -> Option<&mut SpecialItem> { 165 | for e in &mut self.items { 166 | if e.item_id == id { 167 | return Some(e); 168 | } 169 | } 170 | 171 | None 172 | } 173 | } 174 | 175 | #[derive(Debug)] 176 | struct LoopLabel { 177 | start_pc : usize, 178 | index_address : Option, 179 | stepping : DynamicValue, 180 | } 181 | 182 | impl LoopLabel { 183 | fn new(start_pc : usize) -> LoopLabel { 184 | LoopLabel { 185 | start_pc, 186 | index_address : None, 187 | stepping : DynamicValue::Null, 188 | } 189 | } 190 | } 191 | 192 | #[derive(Debug)] 193 | pub struct FunctionFrame { 194 | id : usize, 195 | stack : Vec, 196 | program_counter : usize, 197 | last_comparision : Option, 198 | next_address : usize, 199 | ready : bool, 200 | skip_level : u32, 201 | stack_size : usize, 202 | // Number of special items allocated 203 | num_special_items : usize, 204 | label_stack : Vec, 205 | } 206 | 207 | impl FunctionFrame { 208 | pub fn new(id : usize, stack_size : usize) -> FunctionFrame { 209 | FunctionFrame { 210 | id, 211 | stack : vec![DynamicValue::Null; stack_size], 212 | program_counter : 0, 213 | last_comparision : None, 214 | next_address : 0usize, 215 | ready : false, 216 | skip_level : 0, 217 | stack_size, 218 | label_stack : vec![], 219 | num_special_items : 0, 220 | } 221 | } 222 | } 223 | 224 | #[derive(Clone, Debug)] 225 | pub enum ExecutionStatus { 226 | Normal, 227 | Quit, 228 | Returned, 229 | Halt, 230 | } 231 | 232 | pub struct Registers { 233 | math_a : DynamicValue, 234 | math_b : DynamicValue, 235 | intermediate : DynamicValue, 236 | first_operation : bool, 237 | secondary : DynamicValue, 238 | default_stack_size : usize, 239 | has_quit : bool, 240 | is_interactive : bool, 241 | next_code_index : usize, 242 | next_plugin_index : usize, 243 | } 244 | 245 | impl Registers { 246 | fn default() -> Registers { 247 | Registers { 248 | math_a : DynamicValue::Null, 249 | math_b : DynamicValue::Null, 250 | secondary : DynamicValue::Null, 251 | intermediate : DynamicValue::Null, 252 | first_operation : false, 253 | default_stack_size : STACK_DEFAULT_SIZE, 254 | has_quit : false, 255 | is_interactive : false, 256 | next_code_index : 0, 257 | next_plugin_index : 0, 258 | } 259 | } 260 | } 261 | 262 | pub struct VirtualMachine { 263 | registers : Registers, 264 | callstack : Vec, 265 | stdout: Option>, 266 | stdin: Option>, 267 | code : Vec>, 268 | plugins : Vec, 269 | special_storage : SpecialStorage, 270 | plugin_argument_stack : Vec, 271 | } 272 | 273 | macro_rules! vm_write{ 274 | ($out:expr,$($arg:tt)*) => ({ 275 | if let Some(output) = $out.as_mut(){ 276 | write!(output, $($arg)*) 277 | .map_err(|what| format!("Deu pra escrever não cumpade: {:?}", what)) 278 | }else{ 279 | Ok(()) 280 | } 281 | }) 282 | } 283 | 284 | impl VirtualMachine { 285 | pub fn new() -> VirtualMachine { 286 | VirtualMachine { 287 | registers : Registers::default(), 288 | callstack : vec![], 289 | stdout: None, 290 | stdin: None, 291 | code : vec![], 292 | plugins : vec![], 293 | special_storage : SpecialStorage::new(), 294 | plugin_argument_stack : vec![] 295 | } 296 | } 297 | 298 | fn add_special_item(&mut self, frame_index : usize, data : SpecialItemData) -> Result { 299 | if self.callstack.len() <= frame_index { 300 | return Err("add_special_item : Index é inválido".to_owned()); 301 | } 302 | 303 | self.callstack[frame_index].num_special_items += 1; 304 | 305 | Ok(self.special_storage.add(data, 0u64)) 306 | } 307 | 308 | fn raw_to_dynamic(&mut self, val : RawValue) -> Result { 309 | match val { 310 | RawValue::Text(t) => { 311 | let parent_index = match self.get_last_ready_index() { 312 | Some(s) => s, 313 | None => 0, 314 | }; 315 | 316 | let id = match self.add_special_item(parent_index, SpecialItemData::Text(t)) { 317 | Ok(id) => id, 318 | Err(e) => return Err(e) 319 | }; 320 | 321 | Ok(DynamicValue::Text(id)) 322 | }, 323 | RawValue::Number(n) => Ok(DynamicValue::Number(n)), 324 | RawValue::Integer(i) => Ok(DynamicValue::Integer(i)), 325 | RawValue::Null => Ok(DynamicValue::Null), 326 | } 327 | } 328 | 329 | pub fn set_interactive_mode(&mut self) { 330 | self.registers.is_interactive = true; 331 | } 332 | 333 | pub fn execute_next_instruction(&mut self) -> Result { 334 | if self.callstack.is_empty() { 335 | return Err("Nenhuma função em execução".to_owned()); 336 | } 337 | 338 | let pc = match self.get_current_pc() { 339 | Some(p) => p, 340 | None => return Err("Nenhuma função em execução".to_owned()), 341 | }; 342 | 343 | let id = match self.get_current_id() { 344 | Some(i) => i, 345 | None => return Err("Nenhuma função em execução".to_owned()) 346 | }; 347 | 348 | if self.code.len() <= id { 349 | return Err("ID atual pra função é inválida".to_owned()); 350 | } 351 | 352 | match self.increment_pc() { 353 | Ok(_) => {} 354 | Err(e) => return Err(e), 355 | } 356 | 357 | // The case above doesn't happen anymore and we can just execute it directly 358 | // if self.code[id].len() <= pc {} 359 | 360 | let instruction = self.code[id][pc].clone(); 361 | 362 | self.run(instruction) 363 | } 364 | 365 | pub fn set_stdout(&mut self, write: Option>) -> Option>{ 366 | use std::mem; 367 | mem::replace(&mut self.stdout, write) 368 | } 369 | 370 | pub fn set_stdin(&mut self, read: Option>) -> Option>{ 371 | use std::mem; 372 | mem::replace(&mut self.stdin, read) 373 | } 374 | 375 | pub fn get_current_skip_level(&self) -> u32 { 376 | match self.get_last_ready_ref() { 377 | Some(f) => f.skip_level, 378 | None => 0, 379 | } 380 | } 381 | 382 | fn get_last_ready_ref(&self) -> Option<&FunctionFrame> { 383 | let callstack = &self.callstack; 384 | for frame in callstack.into_iter().rev() { 385 | if frame.ready { 386 | return Some(frame); 387 | } 388 | } 389 | None 390 | } 391 | 392 | pub fn get_last_ready_mut(&mut self) -> Option<&mut FunctionFrame> { 393 | let callstack = &mut self.callstack; 394 | for frame in callstack.into_iter().rev() { 395 | if frame.ready { 396 | return Some(frame); 397 | } 398 | } 399 | None 400 | } 401 | 402 | fn get_current_id(&self) -> Option { 403 | if self.callstack.is_empty() { 404 | None 405 | } else { 406 | match self.get_last_ready_ref() { 407 | Some(f) => Some(f.id), 408 | None => None, 409 | } 410 | } 411 | } 412 | 413 | pub fn get_next_code_id(&self) -> usize { 414 | self.registers.next_code_index 415 | } 416 | 417 | pub fn get_next_plugin_id(&self) -> usize { 418 | self.registers.next_plugin_index 419 | } 420 | 421 | pub fn get_code_for(&mut self, id : usize) -> Option<&mut Vec> { 422 | if self.code.len() <= id { 423 | None 424 | } else { 425 | Some(&mut self.code[id]) 426 | } 427 | } 428 | 429 | pub fn add_new_code(&mut self) -> usize { 430 | let id = self.registers.next_code_index; 431 | self.registers.next_code_index += 1; 432 | self.code.push(vec![]); 433 | 434 | id 435 | } 436 | 437 | pub fn add_new_plugin(&mut self, plugin : PluginFunction) -> usize { 438 | let id = self.get_next_plugin_id(); 439 | self.registers.next_plugin_index += 1; 440 | self.plugins.push(plugin); 441 | 442 | id 443 | } 444 | pub fn get_registers(&self) -> &Registers { 445 | &self.registers 446 | } 447 | 448 | pub fn get_special_storage_ref(&self) -> &SpecialStorage { 449 | &self.special_storage 450 | } 451 | 452 | pub fn get_special_storage_mut(&mut self) -> &mut SpecialStorage { 453 | &mut self.special_storage 454 | } 455 | 456 | pub fn flush_stdout(&mut self) { 457 | if let Some(ref mut out) = self.stdout.as_mut(){ 458 | match out.flush() { 459 | Ok(_) => {} 460 | Err(_) => {} 461 | } 462 | } 463 | } 464 | 465 | fn is_compatible(left : DynamicValue, right : DynamicValue) -> bool { 466 | match left { 467 | DynamicValue::Text(_) => { 468 | if let DynamicValue::Text(_) = right { 469 | true 470 | } else { 471 | false 472 | } 473 | } 474 | DynamicValue::Integer(_) | DynamicValue::Number(_) => { 475 | match right { 476 | DynamicValue::Integer(_) | DynamicValue::Number(_) => true, 477 | _ => false, 478 | } 479 | } 480 | _ => false, 481 | } 482 | } 483 | 484 | fn add_values(&mut self, left : DynamicValue, right : DynamicValue) -> Result { 485 | if ! VirtualMachine::is_compatible(left, right) { 486 | return Err(format!("Add : Os valores não são compatíveis : {:?} e {:?}", left, right)); 487 | } 488 | 489 | match left { 490 | DynamicValue::Integer(l_i) => { 491 | match right { 492 | DynamicValue::Integer(r_i) => Ok(DynamicValue::Integer(l_i + r_i)), 493 | DynamicValue::Number(r_n) => Ok(DynamicValue::Number((l_i as f64) + r_n)), 494 | _ => return Err("Incompatível. Não deveria chegar aqui.".to_owned()), 495 | } 496 | } 497 | DynamicValue::Number(l_n) => { 498 | match right { 499 | DynamicValue::Integer(r_i) => Ok(DynamicValue::Number(l_n + (r_i as f64))), 500 | DynamicValue::Number(r_n) => Ok(DynamicValue::Number(l_n + r_n)), 501 | _ => return Err("Incompatível. Não deveria chegar aqui.".to_owned()), 502 | } 503 | } 504 | DynamicValue::Text(l_t) => { 505 | match right { 506 | DynamicValue::Text(r_t) => { 507 | // Add right value to left node 508 | 509 | let mut result = String::new(); 510 | 511 | { 512 | let left_v = match self.special_storage.get_data_ref(r_t) { 513 | Some(s) => match s { 514 | &SpecialItemData::Text(ref s) => s, 515 | _ => return Err(format!("Erro interno : DynamicValue é texto, mas o id aponta pra outra coisa")) 516 | }, 517 | None => return Err(format!("Add w/ Text : Id {} não encontrada.", r_t)) 518 | }; 519 | 520 | // remove right node 521 | let right_v = match self.special_storage.get_data_ref(l_t) { 522 | Some(s) => match s { 523 | &SpecialItemData::Text(ref s) => s, 524 | _ => return Err(format!("Erro interno : DynamicValue é texto, mas o id aponta pra outra coisa")) 525 | }, 526 | None => return Err(format!("Add w/ Text : Id {} não encontrada.", l_t)) 527 | }; 528 | 529 | if self.registers.first_operation { 530 | result.push_str(right_v); 531 | result.push_str(left_v); 532 | 533 | self.registers.first_operation = false; 534 | } else { 535 | result.push_str(left_v); 536 | result.push_str(right_v); 537 | 538 | } 539 | } 540 | 541 | let parent_index = match self.get_last_ready_index() { 542 | Some(idx) => idx, 543 | None => return Err("Nenhuma função em execução".to_owned()) 544 | }; 545 | 546 | let id = match self.add_special_item(parent_index, SpecialItemData::Text(result)) { 547 | Ok(id) => id, 548 | Err(e) => return Err(e) 549 | }; 550 | 551 | Ok(DynamicValue::Text(id)) 552 | } 553 | _ => return Err("Incompatível. Não deveria chegar aqui.".to_owned()), 554 | } 555 | } 556 | DynamicValue::List(left_id) => { 557 | match right { 558 | DynamicValue::List(right_id) => { 559 | // We must create a new list, add elements from left, then right, then return it 560 | 561 | let mut data = vec![]; 562 | 563 | match self.special_storage.get_data_ref(left_id) { 564 | Some(SpecialItemData::List(ref contents)) => { 565 | for item in contents { 566 | data.push(item.clone()); 567 | } 568 | } 569 | Some(_) => return Err("Erro interno : DynamicValue é uma lista, mas o valor guardado não".to_owned()), 570 | None => return Err("Erro interno : ID inválida pra lista".to_owned()) 571 | } 572 | 573 | match self.special_storage.get_data_ref(right_id) { 574 | Some(SpecialItemData::List(ref contents)) => { 575 | for item in contents { 576 | data.push(item.clone()); 577 | } 578 | } 579 | Some(_) => return Err("Erro interno : DynamicValue é uma lista, mas o valor guardado não".to_owned()), 580 | None => return Err("Erro interno : ID inválida pra lista".to_owned()) 581 | } 582 | 583 | let index = match self.get_last_ready_index() { 584 | Some(i) => i, 585 | None => return Err("Nenhuma função em execução".to_owned()) 586 | }; 587 | 588 | let id = self.add_special_item(index, SpecialItemData::List(data))?; 589 | 590 | Ok(DynamicValue::List(id)) 591 | } 592 | _ => return Err("Operação não suportada entre Listas e outros valores".to_owned()) 593 | } 594 | } 595 | DynamicValue::Null => Ok(DynamicValue::Null), 596 | } 597 | } 598 | 599 | fn sub_values(&mut self, left : DynamicValue, right : DynamicValue) -> Result { 600 | if ! VirtualMachine::is_compatible(left, right) { 601 | return Err(format!("Add : Os valores não são compatíveis : {:?} e {:?}", left, right)); 602 | } 603 | 604 | match left { 605 | DynamicValue::Integer(l_i) => { 606 | match right { 607 | DynamicValue::Integer(r_i) => Ok(DynamicValue::Integer(l_i - r_i)), 608 | DynamicValue::Number(r_n) => Ok(DynamicValue::Number((l_i as f64) - r_n)), 609 | _ => return Err("Incompatível. Não deveria chegar aqui.".to_owned()), 610 | } 611 | } 612 | DynamicValue::Number(l_n) => { 613 | match right { 614 | DynamicValue::Integer(r_i) => Ok(DynamicValue::Number(l_n - (r_i as f64))), 615 | DynamicValue::Number(r_n) => Ok(DynamicValue::Number(l_n - r_n)), 616 | _ => return Err("Incompatível. Não deveria chegar aqui.".to_owned()), 617 | } 618 | } 619 | DynamicValue::Text(_) => return Err("Operação inválida em texto : -".to_owned()), 620 | DynamicValue::Null => Ok(DynamicValue::Null), 621 | DynamicValue::List(_) => return Err("Operação não suportada em listas".to_owned()) 622 | } 623 | } 624 | 625 | fn mul_values(&mut self, left : DynamicValue, right : DynamicValue) -> Result { 626 | if ! VirtualMachine::is_compatible(left, right) { 627 | return Err(format!("Add : Os valores não são compatíveis : {:?} e {:?}", left, right)); 628 | } 629 | 630 | match left { 631 | DynamicValue::Integer(l_i) => { 632 | match right { 633 | DynamicValue::Integer(r_i) => Ok(DynamicValue::Integer(l_i * r_i)), 634 | DynamicValue::Number(r_n) => Ok(DynamicValue::Number((l_i as f64) * r_n)), 635 | _ => return Err("Incompatível. Não deveria chegar aqui.".to_owned()), 636 | } 637 | } 638 | DynamicValue::Number(l_n) => { 639 | match right { 640 | DynamicValue::Integer(r_i) => Ok(DynamicValue::Number(l_n * (r_i as f64))), 641 | DynamicValue::Number(r_n) => Ok(DynamicValue::Number(l_n * r_n)), 642 | _ => return Err("Incompatível. Não deveria chegar aqui.".to_owned()), 643 | } 644 | } 645 | DynamicValue::Text(_) => return Err("Operação inválida em texto : *".to_owned()), 646 | DynamicValue::Null => Ok(DynamicValue::Null), 647 | DynamicValue::List(_) => return Err("Operação não suportada em listas".to_owned()) 648 | } 649 | } 650 | 651 | fn div_values(&mut self, left : DynamicValue, right : DynamicValue) -> Result { 652 | if ! VirtualMachine::is_compatible(left, right) { 653 | return Err(format!("Add : Os valores não são compatíveis : {:?} e {:?}", left, right)); 654 | } 655 | 656 | match left { 657 | DynamicValue::Integer(l_i) => { 658 | match right { 659 | DynamicValue::Integer(r_i) => Ok(DynamicValue::Integer(l_i / r_i)), 660 | DynamicValue::Number(r_n) => Ok(DynamicValue::Number((l_i as f64) / r_n)), 661 | _ => return Err("Incompatível. Não deveria chegar aqui.".to_owned()), 662 | } 663 | } 664 | DynamicValue::Number(l_n) => { 665 | match right { 666 | DynamicValue::Integer(r_i) => Ok(DynamicValue::Number(l_n / (r_i as f64))), 667 | DynamicValue::Number(r_n) => Ok(DynamicValue::Number(l_n / r_n)), 668 | _ => return Err("Incompatível. Não deveria chegar aqui.".to_owned()), 669 | } 670 | } 671 | DynamicValue::Text(_) => return Err("Operação inválida em texto : /".to_owned()), 672 | DynamicValue::Null => Ok(DynamicValue::Null), 673 | DynamicValue::List(_) => return Err("Operação não suportada em listas".to_owned()) 674 | } 675 | } 676 | 677 | fn get_last_comparision(&self) -> Result { 678 | if self.callstack.is_empty() { 679 | return Err("Callstack vazia".to_owned()); 680 | } 681 | 682 | match self.callstack.last().unwrap().last_comparision { 683 | Some(c) => Ok(c), 684 | None => Err("Nenhuma comparação na função atual".to_owned()) 685 | } 686 | } 687 | 688 | fn compare(&self, left : DynamicValue, right : DynamicValue) -> Result { 689 | let comp_numbers: fn(f64, f64) -> Comparision = | l, r | { 690 | if l == r { 691 | Comparision::Equal 692 | } else if l < r { 693 | Comparision::LessThan 694 | } else { 695 | Comparision::MoreThan 696 | } 697 | }; 698 | 699 | let comp = match left { 700 | DynamicValue::Integer(l_i) => { 701 | match right { 702 | DynamicValue::Integer(r_i) => { 703 | if l_i == r_i { 704 | Comparision::Equal 705 | } else if l_i < r_i { 706 | Comparision::LessThan 707 | } else { 708 | Comparision::MoreThan 709 | } 710 | } 711 | DynamicValue::Number(r_n) => comp_numbers(l_i as f64, r_n), 712 | _ => Comparision::NotEqual 713 | } 714 | } 715 | DynamicValue::Number(l_n) => { 716 | match right { 717 | DynamicValue::Number(r_n) => { 718 | comp_numbers(l_n, r_n) 719 | } 720 | DynamicValue::Integer(r_i) => { 721 | comp_numbers(l_n, r_i as f64) 722 | } 723 | _ => Comparision::NotEqual, 724 | } 725 | } 726 | DynamicValue::Text(l_t) => { 727 | match right { 728 | DynamicValue::Text(r_t) => { 729 | let ltext = match self.special_storage.get_data_ref(l_t) { 730 | Some(s) => match s { 731 | &SpecialItemData::Text(ref s) => s, 732 | _ => return Err(format!("Erro interno : DynamicValue é texto, mas o id aponta pra outra coisa")) 733 | }, 734 | None => return Err(format!("Erro : TextID não encontrada : {}", l_t)), 735 | }; 736 | 737 | let rtext = match self.special_storage.get_data_ref(r_t) { 738 | Some(s) => match s { 739 | &SpecialItemData::Text(ref s) => s, 740 | _ => return Err(format!("Erro interno : DynamicValue é texto, mas o id aponta pra outra coisa")) 741 | }, 742 | None => return Err(format!("Erro : TextID não encontrada : {}", r_t)), 743 | }; 744 | 745 | let llen = ltext.len(); 746 | let rlen = rtext.len(); 747 | 748 | if llen > rlen { 749 | Comparision::MoreThan 750 | } else if llen < rlen { 751 | Comparision::LessThan 752 | } else { 753 | if ltext == rtext { 754 | Comparision::Equal 755 | } else { 756 | Comparision::NotEqual 757 | } 758 | } 759 | } 760 | _ => Comparision::NotEqual 761 | } 762 | } 763 | DynamicValue::List(left_id) => { 764 | match right { 765 | DynamicValue::List(right_id) => { 766 | let left_list = match self.special_storage.get_data_ref(left_id) { 767 | Some(SpecialItemData::List(ref list)) => list.clone(), 768 | Some(_) => return Err("Erro interno : DynamicValue é uma lista mas o item guardado não".to_owned()), 769 | None => return Err("ID não existe".to_owned()) 770 | }; 771 | 772 | let right_list = match self.special_storage.get_data_ref(right_id) { 773 | Some(SpecialItemData::List(ref list)) => list.clone(), 774 | Some(_) => return Err("Erro interno : DynamicValue é uma lista mas o item guardado não".to_owned()), 775 | None => return Err("ID não existe".to_owned()) 776 | }; 777 | 778 | if left_list.len() != right_list.len() { 779 | Comparision::NotEqual 780 | } else { 781 | 782 | for i in 0..left_list.len() { 783 | match self.compare(*left_list[i], *right_list[i]) { 784 | Ok(Comparision::Equal) => {}, 785 | Ok(_) => return Ok(Comparision::NotEqual), 786 | Err(e) => return Err(e) 787 | } 788 | } 789 | 790 | Comparision::Equal 791 | } 792 | } 793 | _ => Comparision::NotEqual, 794 | } 795 | } 796 | DynamicValue::Null => { 797 | match right { 798 | DynamicValue::Null => Comparision::Equal, 799 | _ => Comparision::NotEqual, 800 | } 801 | } 802 | }; 803 | 804 | Ok(comp) 805 | } 806 | 807 | fn set_last_comparision(&mut self, comp : Comparision) -> Result<(), String> { 808 | if self.callstack.is_empty() { 809 | return Err("Callstack tá vazia. Provavelmente é erro interno".to_owned()); 810 | } 811 | 812 | self.callstack.last_mut().unwrap().last_comparision = Some(comp); 813 | 814 | Ok(()) 815 | } 816 | 817 | // This function doesn't search all the callstack, just the first frame 818 | fn get_last_ready_index(&self) -> Option { 819 | if self.callstack.is_empty() { 820 | None 821 | } 822 | else if self.callstack.len() < 2 { 823 | if self.callstack[0].ready { 824 | Some(0) 825 | } else { 826 | None 827 | } 828 | } else { 829 | let last = self.callstack.len() - 1; 830 | 831 | if self.callstack[last].ready { 832 | Some(last) 833 | } else { 834 | Some(last - 1) 835 | } 836 | } 837 | } 838 | 839 | fn write_to(&mut self, val : DynamicValue, stack_index : usize, address : usize) -> Result<(), String> { 840 | if self.callstack.len() <= stack_index { 841 | return Err(format!("Index de frame inválido : {}", stack_index)); 842 | } 843 | 844 | let frame = &mut self.callstack[stack_index]; 845 | 846 | if frame.stack.len() <= address { 847 | return Err("Endereço out-of-bounds".to_owned()); 848 | } 849 | 850 | // Check if the value we're writing to is a special item 851 | // if it is, we need to decrement it first 852 | 853 | match frame.stack[address] { 854 | DynamicValue::List(id) => self.special_storage.decrement_ref(id)?, 855 | DynamicValue::Text(id) => self.special_storage.decrement_ref(id)?, 856 | _ => {} 857 | }; 858 | 859 | // If the value we're writing is a special item, increment its ref count 860 | 861 | match val { 862 | DynamicValue::List(id) => self.special_storage.increment_ref(id)?, 863 | DynamicValue::Text(id) => self.special_storage.increment_ref(id)?, 864 | _ => {} 865 | }; 866 | 867 | frame.stack[address] = val; 868 | 869 | Ok(()) 870 | } 871 | 872 | fn increase_skip_level(&mut self) -> Result<(), String> { 873 | match self.get_last_ready_mut() { 874 | Some(f) => f.skip_level += 1, 875 | None => return Err("Nenhuma função ready em execução".to_owned()) 876 | } 877 | 878 | Ok(()) 879 | } 880 | 881 | fn decrease_skip_level(&mut self) -> Result<(), String> { 882 | match self.get_last_ready_mut() { 883 | Some(f) => f.skip_level -= 1, 884 | None => return Err("Nenhuma função ready em execução".to_owned()) 885 | } 886 | 887 | Ok(()) 888 | } 889 | 890 | fn read_from_id(&mut self, index : usize, address : usize) -> Result { 891 | if self.callstack.len() < index { 892 | return Err(format!("Index out of bounds for read : {}", index)); 893 | } 894 | 895 | let val = { 896 | 897 | let frame = &mut self.callstack[index]; 898 | 899 | if frame.stack.len() <= address { 900 | return Err("Erro : Endereço pra variável é inválido".to_owned()); 901 | } 902 | 903 | frame.stack[address] 904 | }; 905 | 906 | Ok(val) 907 | } 908 | 909 | pub fn unset_quit(&mut self) { 910 | self.registers.has_quit = false; 911 | } 912 | 913 | pub fn has_quit(&self) -> bool { 914 | self.registers.has_quit 915 | } 916 | 917 | pub fn get_current_pc(&self) -> Option { 918 | match self.get_last_ready_ref() { 919 | Some(f) => Some(f.program_counter), 920 | None => None 921 | } 922 | } 923 | 924 | pub fn increment_pc(&mut self) -> Result<(), String> { 925 | match self.get_last_ready_mut() { 926 | Some(f) => f.program_counter += 1, 927 | None => return Err("Nenhuma função em execução".to_owned()) 928 | } 929 | 930 | Ok(()) 931 | } 932 | 933 | pub fn decrement_pc(&mut self) -> Result<(), String> { 934 | match self.get_last_ready_mut() { 935 | Some(f) => f.program_counter -= 1, 936 | None => return Err("Nenhuma função em execução".to_owned()) 937 | } 938 | 939 | Ok(()) 940 | } 941 | 942 | fn conv_to_string(&mut self, val : DynamicValue) -> Result { 943 | match val { 944 | DynamicValue::Text(t) => { 945 | let s = match self.special_storage.get_data_ref(t) { 946 | Some(s) => match s { 947 | &SpecialItemData::Text(ref s) => s, 948 | _ => return Err(format!("Erro interno : DynamicValue é texto, mas o id aponta pra outra coisa")) 949 | }, 950 | None => return Err("Invalid string ID".to_owned()), 951 | }; 952 | 953 | Ok(s.clone()) 954 | } 955 | DynamicValue::Integer(i) => Ok(format!("{}", i)), 956 | DynamicValue::Number(n) => Ok(format!("{}", n)), 957 | DynamicValue::Null => Ok(String::from("")), 958 | DynamicValue::List(id) => { 959 | let list = match self.special_storage.get_data_ref(id) { 960 | Some(SpecialItemData::List(ref list)) => list.clone(), 961 | Some(_) => return Err("Erro interno : DynamicValue é uma lista, item interno não".to_owned()), 962 | None => return Err("ID inválida pra lista".to_owned()) 963 | }; 964 | 965 | let mut result = String::from("[ "); 966 | let mut first = true; 967 | 968 | for item in list { 969 | if !first { 970 | result.push_str(", "); 971 | } else { 972 | first = false; 973 | } 974 | 975 | // kek 976 | let is_str = if let DynamicValue::Text(_) = *item { 977 | true 978 | } else { 979 | false 980 | }; 981 | 982 | let s = self.conv_to_string(*item)?; 983 | 984 | if is_str { 985 | result.push_str("\""); 986 | } 987 | 988 | result.push_str(s.as_str()); 989 | 990 | if is_str { 991 | result.push_str("\""); 992 | } 993 | } 994 | 995 | result.push_str(" ]"); 996 | 997 | Ok(result) 998 | } 999 | } 1000 | } 1001 | 1002 | fn conv_to_int(&mut self, val : DynamicValue) -> Result { 1003 | match val { 1004 | DynamicValue::Text(t) => { 1005 | let text = match self.special_storage.get_data_ref(t) { 1006 | Some(s) => match s { 1007 | &SpecialItemData::Text(ref s) => s, 1008 | _ => return Err(format!("Erro interno : DynamicValue é texto, mas o id aponta pra outra coisa")) 1009 | }, 1010 | None => return Err("Invalid text id".to_owned()) 1011 | }; 1012 | 1013 | let i = match text.parse::() { 1014 | Ok(i) => i, 1015 | Err(_) => return Err(format!("Não foi possível converter \"{}\" pra Int", text)) 1016 | }; 1017 | 1018 | Ok(i) 1019 | } 1020 | DynamicValue::Number(n) => Ok(n as IntegerType), 1021 | DynamicValue::Integer(i) => Ok(i), 1022 | DynamicValue::Null => return Err("Convert : ".to_owned()), 1023 | DynamicValue::List(_) => return Err("Não é possível converter uma lista pra inteiro".to_owned()) 1024 | } 1025 | } 1026 | 1027 | fn conv_to_num(&mut self, val : DynamicValue) -> Result { 1028 | match val { 1029 | DynamicValue::Text(t) => { 1030 | let text = match self.special_storage.get_data_ref(t) { 1031 | Some(s) => match s { 1032 | &SpecialItemData::Text(ref s) => s, 1033 | _ => return Err(format!("Erro interno : DynamicValue é texto, mas o id aponta pra outra coisa")) 1034 | }, 1035 | None => return Err("Invalid text id".to_owned()) 1036 | }; 1037 | 1038 | let n = match text.parse::() { 1039 | Ok(n) => n, 1040 | Err(_) => return Err(format!("Não foi possível converter \"{}\" pra Num", text)) 1041 | }; 1042 | 1043 | Ok(n) 1044 | } 1045 | DynamicValue::Number(n) => Ok(n), 1046 | DynamicValue::Integer(i) => Ok(i as f64), 1047 | DynamicValue::Null => return Err("Convert : ".to_owned()), 1048 | DynamicValue::List(_) => return Err("Não é possível converter uma lista pra número".to_owned()) 1049 | } 1050 | } 1051 | 1052 | fn last_comparision_matches(&self, req : ComparisionRequest) -> Result { 1053 | let last = match self.get_last_comparision() { 1054 | Ok(c) => c, 1055 | Err(e) => return Err(e) 1056 | }; 1057 | 1058 | match req { 1059 | ComparisionRequest::Equal => Ok(last == Comparision::Equal), 1060 | ComparisionRequest::NotEqual => Ok(last != Comparision::Equal), 1061 | ComparisionRequest::Less => Ok(last == Comparision::LessThan), 1062 | ComparisionRequest::LessOrEqual => Ok(last == Comparision::LessThan || last == Comparision::Equal), 1063 | ComparisionRequest::More => Ok(last == Comparision::MoreThan), 1064 | ComparisionRequest::MoreOrEqual => Ok(last == Comparision::MoreThan || last == Comparision::Equal), 1065 | } 1066 | } 1067 | 1068 | pub fn set_stack_size(&mut self, size : usize) { 1069 | self.registers.default_stack_size = size; 1070 | } 1071 | 1072 | fn set_current_pc(&mut self, pc : usize) -> Result<(), String> { 1073 | match self.get_last_ready_mut() { 1074 | Some(f) => f.program_counter = pc, 1075 | None => return Err("Nenhuma função em execução".to_owned()) 1076 | }; 1077 | 1078 | Ok(()) 1079 | } 1080 | 1081 | pub fn print_string(&mut self, s : &str) -> Result<(), String> { 1082 | vm_write!(self.stdout, "{}", s) 1083 | } 1084 | 1085 | pub fn print_value(&mut self, val : DynamicValue) -> Result<(), String> { 1086 | match val { 1087 | DynamicValue::Integer(i) => vm_write!(self.stdout, "{}", i)?, 1088 | DynamicValue::Number(n) => vm_write!(self.stdout, "{}", n)?, 1089 | DynamicValue::Text(t) => { 1090 | let t = match self.special_storage.get_data_ref(t) { 1091 | Some(s) => match s { 1092 | &SpecialItemData::Text(ref s) => s, 1093 | _ => return Err(format!("Erro interno : DynamicValue é texto, mas o id aponta pra outra coisa")) 1094 | }, 1095 | None => return Err(format!("MainPrint : Não foi encontrado text com ID {}", t)), 1096 | }; 1097 | 1098 | vm_write!(self.stdout, "{}", t)? 1099 | } 1100 | DynamicValue::List(id) => { 1101 | let string = match self.conv_to_string(DynamicValue::List(id)) { 1102 | Ok(s) => s, 1103 | Err(e) => return Err(e) 1104 | }; 1105 | vm_write!(self.stdout, "(Lista) {}", string)?; 1106 | } 1107 | DynamicValue::Null => vm_write!(self.stdout, "")?, 1108 | } 1109 | 1110 | Ok(()) 1111 | } 1112 | 1113 | pub fn run(&mut self, inst : Instruction) -> Result { 1114 | if self.get_current_skip_level() > 0 { 1115 | if let Instruction::EndConditionalBlock = inst { 1116 | self.decrease_skip_level()?; 1117 | } 1118 | 1119 | return Ok(ExecutionStatus::Normal); 1120 | } 1121 | 1122 | match inst { 1123 | Instruction::EndConditionalBlock => {}, 1124 | Instruction::PrintMathBDebug => { 1125 | match self.registers.math_b { 1126 | DynamicValue::Integer(i) => vm_write!(self.stdout, "(Integer) {}\n", i)?, 1127 | DynamicValue::Number(n) => vm_write!(self.stdout, "(Number) {}\n", n)?, 1128 | DynamicValue::Text(t) => { 1129 | let t = match self.special_storage.get_data_ref(t) { 1130 | Some(s) => match s { 1131 | &SpecialItemData::Text(ref s) => s, 1132 | _ => return Err(format!("Erro interno : DynamicValue é texto, mas o id aponta pra outra coisa")) 1133 | }, 1134 | None => return Err(format!("MainPrint : Não foi encontrado text com ID {}", t)), 1135 | }; 1136 | 1137 | vm_write!(self.stdout, "(Text) \"{}\"\n", t)? 1138 | } 1139 | DynamicValue::Null => vm_write!(self.stdout, "\n")?, 1140 | DynamicValue::List(id) => { 1141 | let string = match self.conv_to_string(DynamicValue::List(id)) { 1142 | Ok(s) => s, 1143 | Err(e) => return Err(e) 1144 | }; 1145 | vm_write!(self.stdout, "{}\n", string)?; 1146 | } 1147 | } 1148 | 1149 | self.flush_stdout(); 1150 | } 1151 | Instruction::PrintMathB => { 1152 | let val = self.registers.math_b; 1153 | 1154 | self.print_value(val)?; 1155 | } 1156 | Instruction::PrintNewLine => { 1157 | vm_write!(self.stdout, "\n")? 1158 | } 1159 | Instruction::Quit => { 1160 | self.registers.has_quit = true; 1161 | 1162 | return Ok(ExecutionStatus::Quit); 1163 | } 1164 | Instruction::FlushStdout => { 1165 | self.flush_stdout(); 1166 | } 1167 | Instruction::Compare => { 1168 | let result = match self.compare(self.registers.math_a, self.registers.math_b) { 1169 | Ok(c) => c, 1170 | Err(e) => return Err(e), 1171 | }; 1172 | 1173 | match self.set_last_comparision(result) { 1174 | Ok(_) => {} 1175 | Err(e) => return Err(e) 1176 | } 1177 | } 1178 | Instruction::Return => { 1179 | 1180 | if self.callstack.len() == 1 { 1181 | self.registers.has_quit = true; 1182 | 1183 | return Ok(ExecutionStatus::Quit); 1184 | } 1185 | 1186 | match self.callstack.pop() { 1187 | Some(_) => {} 1188 | None => return Err("Erro no return : Nenhuma função em execução".to_owned()) 1189 | } 1190 | 1191 | let index = self.callstack.len() - 1; 1192 | let val = self.registers.math_b; 1193 | match self.write_to(val, index, 0) { 1194 | Ok(_) => {} 1195 | Err(e) => return Err(e) 1196 | } 1197 | 1198 | // If this is the global function and we're in interactive mode, print the return value 1199 | 1200 | if self.callstack.len() == 1 && self.registers.is_interactive { 1201 | self.run(Instruction::PrintMathBDebug)?; // Return val is in math_b already 1202 | } 1203 | 1204 | return Ok(ExecutionStatus::Returned); 1205 | } 1206 | Instruction::ExecuteIf(req) => { 1207 | if self.get_current_skip_level() > 0 { 1208 | self.increase_skip_level()?; 1209 | } else { 1210 | if ! self.last_comparision_matches(req)? { 1211 | self.increase_skip_level()?; 1212 | } 1213 | } 1214 | } 1215 | Instruction::MakeNewFrame(id) => { 1216 | // Add a new, not ready frame to the callstack 1217 | 1218 | let frame = FunctionFrame::new(id, self.registers.default_stack_size); 1219 | 1220 | self.callstack.push(frame); 1221 | } 1222 | Instruction::SetLastFrameReady => { 1223 | // Set the last frame to ready 1224 | 1225 | if ! self.callstack.is_empty() { 1226 | self.callstack.last_mut().unwrap().ready = true; 1227 | } else { 1228 | return Err("Callstack vazia".to_owned()); 1229 | } 1230 | } 1231 | Instruction::AssertMathBCompatible(kind) => { 1232 | let v = self.registers.math_b; 1233 | 1234 | match v { 1235 | DynamicValue::Null => return Err("Tipo incompatível : Null".to_owned()), 1236 | DynamicValue::Text(_) => { 1237 | if kind == TypeKind::Text { 1238 | // Ok 1239 | } else { 1240 | return Err("Tipo incompatível : Texto".to_owned()); 1241 | } 1242 | } 1243 | DynamicValue::Integer(_) => { 1244 | if kind == TypeKind::Integer || kind == TypeKind::Number { 1245 | // Ok 1246 | } else { 1247 | return Err("Tipo incompatível : Int ou Num".to_owned()); 1248 | } 1249 | } 1250 | DynamicValue::Number(_) => { 1251 | if kind == TypeKind::Number { 1252 | // Ok 1253 | } else { 1254 | return Err("Tipo incompatível : Number".to_owned()); 1255 | } 1256 | } 1257 | DynamicValue::List(_) => { 1258 | if kind == TypeKind::List { 1259 | // Ok 1260 | } else { 1261 | return Err("Tipo incompatível : Lista".to_owned()); 1262 | } 1263 | } 1264 | } 1265 | } 1266 | Instruction::ReadInput => { 1267 | let line = if let Some(ref mut input) = self.stdin.as_mut(){ 1268 | let mut line = String::new(); 1269 | match input.read_line(&mut line) { 1270 | Ok(_) => {} 1271 | Err(e) => return Err(format!("Erro lendo input : {:?}", e)) 1272 | }; 1273 | 1274 | let last_index = line.len() - 1; 1275 | line.remove(last_index); 1276 | 1277 | Some(line) 1278 | } else { None }; 1279 | 1280 | let parent_index = match self.get_last_ready_index() { 1281 | Some(s) => s, 1282 | None => return Err("Nenhuma função em execução".to_owned()) 1283 | }; 1284 | 1285 | if let Some(line) = line { 1286 | let id = match self.add_special_item(parent_index, SpecialItemData::Text(line)) { 1287 | Ok(id) => id, 1288 | Err(e) => return Err(e) 1289 | }; 1290 | 1291 | self.registers.intermediate = DynamicValue::Text(id); 1292 | } 1293 | } 1294 | Instruction::ConvertToNum => { 1295 | let val = self.registers.math_b; 1296 | 1297 | let v = match self.conv_to_num(val) { 1298 | Ok(v) => v, 1299 | Err(e) => return Err(e) 1300 | }; 1301 | 1302 | self.registers.math_b = DynamicValue::Number(v); 1303 | } 1304 | Instruction::ConvertToInt => { 1305 | let val = self.registers.math_b; 1306 | 1307 | let v = match self.conv_to_int(val) { 1308 | Ok(v) => v, 1309 | Err(e) => return Err(e) 1310 | }; 1311 | 1312 | self.registers.math_b = DynamicValue::Integer(v); 1313 | } 1314 | Instruction::ConvertToString => { 1315 | let val = self.registers.math_b; 1316 | 1317 | let id = if let DynamicValue::Text(id) = val { 1318 | id 1319 | } else { 1320 | let v = match self.conv_to_string(val) { 1321 | Ok(v) => v, 1322 | Err(e) => return Err(e) 1323 | }; 1324 | 1325 | let parent_index = match self.get_last_ready_index() { 1326 | Some(s) => s, 1327 | None => return Err("Nenhuma função em execução".to_owned()) 1328 | }; 1329 | 1330 | match self.add_special_item(parent_index, SpecialItemData::Text(v)) { 1331 | Ok(id) => id, 1332 | Err(e) => return Err(e) 1333 | } 1334 | }; 1335 | 1336 | self.registers.math_b = DynamicValue::Text(id); 1337 | } 1338 | Instruction::PushValMathA(val) => { 1339 | match self.raw_to_dynamic(val) { 1340 | Ok(v) => self.registers.math_a = v, 1341 | Err(e) => return Err(e) 1342 | } 1343 | } 1344 | Instruction::PushValMathB(val) => { 1345 | match self.raw_to_dynamic(val) { 1346 | Ok(v) => self.registers.math_b = v, 1347 | Err(e) => return Err(e) 1348 | } 1349 | } 1350 | Instruction::PushIntermediateToA => { 1351 | self.registers.math_a = self.registers.intermediate; 1352 | } 1353 | Instruction::PushIntermediateToB => { 1354 | self.registers.math_b = self.registers.intermediate; 1355 | } 1356 | Instruction::ReadGlobalVarFrom(addr) => { 1357 | let val = match self.read_from_id(0, addr) { 1358 | Ok(v) => v, 1359 | Err(e) => return Err(e) 1360 | }; 1361 | 1362 | self.registers.intermediate = val; 1363 | } 1364 | Instruction::WriteGlobalVarTo(addr) => { 1365 | let index = 0; 1366 | let val = self.registers.math_b; 1367 | 1368 | match self.write_to(val, index, addr) { 1369 | Ok(_) => {} 1370 | Err(e) => return Err(e), 1371 | } 1372 | } 1373 | Instruction::ReadVarFrom(addr) => { 1374 | let index = match self.get_last_ready_index() { 1375 | Some(i) => i, 1376 | None => return Err("Nenhuma função pronta em execução".to_owned()), 1377 | }; 1378 | 1379 | let val = match self.read_from_id(index, addr) { 1380 | Ok(v) => v, 1381 | Err(e) => return Err(e) 1382 | }; 1383 | 1384 | self.registers.intermediate = val; 1385 | } 1386 | Instruction::WriteVarTo(addr) => { 1387 | let index = match self.get_last_ready_index() { 1388 | Some(i) => i, 1389 | None => return Err("Nenhuma função pronta em execução".to_owned()), 1390 | }; 1391 | 1392 | let val = self.registers.math_b; 1393 | 1394 | match self.write_to(val, index, addr) { 1395 | Ok(_) => {} 1396 | Err(e) => return Err(e) 1397 | } 1398 | } 1399 | Instruction::WriteVarToLast(addr) => { 1400 | let index = self.callstack.len() - 1; 1401 | let val = self.registers.math_b; 1402 | 1403 | match self.write_to(val, index, addr) { 1404 | Ok(_) => {} 1405 | Err(e) => return Err(e), 1406 | } 1407 | } 1408 | Instruction::Add => { 1409 | let left = self.registers.math_a; 1410 | let right = self.registers.math_b; 1411 | let res = match self.add_values(left, right) { 1412 | Ok(v) => v, 1413 | Err(e) => return Err(e) 1414 | }; 1415 | 1416 | self.registers.math_b = res; 1417 | } 1418 | Instruction::Mul => { 1419 | let left = self.registers.math_a; 1420 | let right = self.registers.math_b; 1421 | let res = match self.mul_values(left, right) { 1422 | Ok(v) => v, 1423 | Err(e) => return Err(e) 1424 | }; 1425 | 1426 | self.registers.math_b = res; 1427 | } 1428 | Instruction::Div => { 1429 | let left = self.registers.math_a; 1430 | let right = self.registers.math_b; 1431 | let res = match self.div_values(left, right) { 1432 | Ok(v) => v, 1433 | Err(e) => return Err(e) 1434 | }; 1435 | 1436 | self.registers.math_b = res; 1437 | } 1438 | Instruction::Sub => { 1439 | let left = self.registers.math_a; 1440 | let right = self.registers.math_b; 1441 | let res = match self.sub_values(left, right) { 1442 | Ok(v) => v, 1443 | Err(e) => return Err(e) 1444 | }; 1445 | 1446 | self.registers.math_b = res; 1447 | } 1448 | Instruction::SwapMath => { 1449 | let tmp = self.registers.math_b; 1450 | self.registers.math_b = self.registers.math_a; 1451 | self.registers.math_a = tmp; 1452 | } 1453 | Instruction::ClearMath => { 1454 | self.registers.math_a = DynamicValue::Null; 1455 | self.registers.math_b = DynamicValue::Null; 1456 | self.registers.intermediate = DynamicValue::Null; 1457 | } 1458 | Instruction::AddLoopLabel => { 1459 | let next_pc = match self.get_current_pc() { 1460 | Some(p) => p, 1461 | None => return Err("Nenhuma função em execução".to_owned()) 1462 | }; 1463 | 1464 | match self.get_last_ready_mut() { 1465 | Some(f) => f.label_stack.push(LoopLabel::new(next_pc)), 1466 | None => return Err("Nenhuma função em execução".to_owned()) 1467 | } 1468 | } 1469 | Instruction::RestoreLoopLabel => { 1470 | let (mut address, mut step) = (None, DynamicValue::Null); 1471 | 1472 | let pc = match self.get_last_ready_ref() { 1473 | Some(f) => { 1474 | let label = match f.label_stack.last() { 1475 | Some(l) => l, 1476 | None => return Err("Restore : Nenhuma label disponível".to_owned()) 1477 | }; 1478 | 1479 | if let Some(addr) = label.index_address { 1480 | address = Some(addr); 1481 | step = label.stepping; 1482 | } 1483 | 1484 | label.start_pc 1485 | } 1486 | None => return Err("Nenhuma função em execução".to_owned()) 1487 | }; 1488 | 1489 | self.set_current_pc(pc)?; 1490 | 1491 | if let Some(address) = address { 1492 | let index = match self.get_last_ready_index() { 1493 | Some(i) => i, 1494 | None => return Err("Nenhuma função pronta em execução".to_owned()), 1495 | }; 1496 | 1497 | let current = self.read_from_id(index, address)?; 1498 | 1499 | let result = self.add_values(current, step)?; 1500 | 1501 | match self.write_to(result, index, address) { 1502 | Ok(_) => {} 1503 | Err(e) => return Err(e) 1504 | } 1505 | } 1506 | } 1507 | Instruction::PopLoopLabel => { 1508 | match self.get_last_ready_mut() { 1509 | Some(f) => { 1510 | match f.label_stack.pop() { 1511 | Some(_) => {} 1512 | None => return Err("Não havia nenhuma label pra remover".to_owned()) 1513 | } 1514 | } 1515 | None => return Err("Nenhuma função em execução".to_owned()) 1516 | } 1517 | } 1518 | Instruction::RegisterIncrementOnRestore(address) => { 1519 | // Since this instruction is right after AddLabel, this is going to be executed each iteration 1520 | // and since we don't want that, we'll also increment the PC on the label 1521 | 1522 | let stepping = self.registers.math_b; 1523 | 1524 | match self.get_last_ready_mut() { 1525 | Some(s) => match s.label_stack.last_mut() { 1526 | Some(l) => { 1527 | l.stepping = stepping; 1528 | l.index_address = Some(address); 1529 | // As explained above 1530 | l.start_pc += 1; 1531 | } 1532 | None => return Err("Função atual não tem nenhuma label".to_owned()), 1533 | } 1534 | None => return Err("Nenhuma função em execução".to_owned()) 1535 | }; 1536 | } 1537 | Instruction::SetFirstExpressionOperation => { 1538 | self.registers.first_operation = true; 1539 | } 1540 | Instruction::MakeNewList => { 1541 | let index = match self.get_last_ready_index() { 1542 | Some(i) => i, 1543 | None => return Err("Nenhuma função em execução".to_owned()) 1544 | }; 1545 | 1546 | let data = match self.add_special_item(index, SpecialItemData::List(vec![])) { 1547 | Ok(d) => d, 1548 | Err(e) => return Err(e) 1549 | }; 1550 | 1551 | self.registers.math_b = DynamicValue::List(data); 1552 | } 1553 | Instruction::IndexList => { 1554 | let index = if let DynamicValue::Integer(i) = self.registers.math_b { 1555 | i 1556 | } else { 1557 | return Err(format!("Esperado um índice na forma de um inteiro, encontrado {:?}", self.registers.math_b)) 1558 | }; 1559 | 1560 | let value = { 1561 | if let DynamicValue::List(id) = self.registers.intermediate { 1562 | match self.special_storage.get_data_ref(id) { 1563 | Some(SpecialItemData::List(ref d)) => { 1564 | if index as usize >= d.len() { 1565 | return Err(format!("Erro : Index depois do final da lista. Tamanho da lista : {}", d.len())); 1566 | } 1567 | 1568 | *d[index as usize] 1569 | } 1570 | Some(_) => return Err(format!("Erro interno : DynamicValue é uma lista, mas o item na memória não")), 1571 | None => return Err("Erro interno : ID inválida".to_owned()) 1572 | } 1573 | } else { 1574 | return Err(format!("Variável passada não é uma lista")); 1575 | } 1576 | }; 1577 | 1578 | self.registers.math_b = value; 1579 | } 1580 | Instruction::AddToListAtIndex => { 1581 | let index = if let DynamicValue::Integer(val) = self.registers.secondary { 1582 | Some(val) 1583 | } else { 1584 | None 1585 | }; 1586 | 1587 | let value = self.registers.math_b; 1588 | 1589 | let list_id = if let DynamicValue::List(id) = self.registers.intermediate { 1590 | id 1591 | } else { 1592 | return Err(format!("AddListToIndex : A variável não é uma lista")); 1593 | }; 1594 | 1595 | let list = match self.special_storage.get_data_mut(list_id) { 1596 | Some(l) => match l { 1597 | SpecialItemData::List(ref mut list) => list, 1598 | _ => return Err("Item especial com a ID passada não é uma lista".to_owned()) 1599 | } 1600 | None => return Err("ID da lista não encontrada".to_owned()) 1601 | }; 1602 | 1603 | if let Some(i) = index { 1604 | if i as usize >= list.len() { 1605 | list.push(Box::new(value)); 1606 | } else { 1607 | list.insert(i as usize, Box::new(value)); 1608 | } 1609 | } else { 1610 | list.push(Box::new(value)); 1611 | } 1612 | } 1613 | Instruction::ClearSecondary => { 1614 | self.registers.secondary = DynamicValue::Null; 1615 | } 1616 | Instruction::PushMathBToSeconday => { 1617 | let val = self.registers.math_b; 1618 | self.registers.secondary = val; 1619 | } 1620 | Instruction::RemoveFromListAtIndex => { 1621 | let index = if let DynamicValue::Integer(i) = self.registers.math_b { 1622 | i 1623 | } else { 1624 | return Err(format!("Esperado um inteiro como índice pra lista, encontrado {:?}", self.registers.math_b)); 1625 | }; 1626 | 1627 | let id = if let DynamicValue::List(id) = self.registers.intermediate { 1628 | id 1629 | } else { 1630 | return Err("A variável não é uma lista".to_owned()); 1631 | }; 1632 | 1633 | match self.special_storage.get_data_mut(id) { 1634 | Some(SpecialItemData::List(ref mut list)) => { 1635 | if index as usize >= list.len() { 1636 | return Err(format!("Erro : Index maior que a lista. Tamanho da lista : {}", list.len())); 1637 | } 1638 | 1639 | list.remove(index as usize); 1640 | } 1641 | Some(_) => return Err("Erro interno : DynamicValue é uma lista mas o valor na memória não".to_owned()), 1642 | None => return Err("Erro interno : ID não encontrada".to_owned()) 1643 | } 1644 | } 1645 | Instruction::QueryListSize => { 1646 | let id = if let DynamicValue::List(id) = self.registers.intermediate { 1647 | id 1648 | } else { 1649 | return Err("QueryListSize : Variável não é uma lista".to_owned()); 1650 | }; 1651 | 1652 | let list = match self.special_storage.get_data_ref(id) { 1653 | Some(l) => match l { 1654 | SpecialItemData::List(l) => l, 1655 | _ => return Err("Erro interno : ID não aponta pra uma lista".to_owned()) 1656 | } 1657 | None => return Err("Não encontrado item com a ID passada".to_owned()) 1658 | }; 1659 | 1660 | let val = DynamicValue::Integer(list.len() as IntegerType); 1661 | 1662 | self.registers.math_b = val; 1663 | } 1664 | Instruction::CallPlugin(address, num) => { 1665 | if address > self.plugins.len() { 1666 | return Err("CallPlugin : Endereço inválido".to_owned()); 1667 | } 1668 | 1669 | let plugin = self.plugins[address]; 1670 | 1671 | if num > self.plugin_argument_stack.len() { 1672 | return Err(format!("CallPlugin : Número de argumentos maior que a quantidade de argumentos disponíveis")); 1673 | } 1674 | 1675 | let mut args = Vec::with_capacity(num); 1676 | 1677 | for _ in 0..num { 1678 | let val = match self.plugin_argument_stack.pop() { 1679 | Some(v) => v, 1680 | None => unreachable!() 1681 | }; 1682 | 1683 | args.push(val); 1684 | } 1685 | 1686 | let result = plugin(args, self)?; 1687 | 1688 | if let Some(value) = result { 1689 | let index = self.callstack.len() - 1; 1690 | self.write_to(value, index, 0)?; 1691 | 1692 | if self.registers.is_interactive && self.callstack.len() == 1 { 1693 | let tmp = self.registers.math_b; 1694 | 1695 | self.registers.math_b = value; 1696 | 1697 | self.run(Instruction::PrintMathBDebug)?; 1698 | 1699 | self.registers.math_b = tmp; 1700 | } 1701 | } 1702 | } 1703 | Instruction::PushMathBPluginArgument => { 1704 | let val = self.registers.math_b; 1705 | self.plugin_argument_stack.push(val); 1706 | } 1707 | Instruction::IncreaseSkippingLevel => { 1708 | self.increase_skip_level()?; 1709 | } 1710 | Instruction::Halt => { 1711 | return Ok(ExecutionStatus::Halt); 1712 | } 1713 | Instruction::TryDecrementRefAt(address) => { 1714 | let index = match self.get_last_ready_index() { 1715 | Some(i) => i, 1716 | None => return Err("".to_owned()), 1717 | }; 1718 | 1719 | match self.read_from_id(index, address) { 1720 | Ok(v) => match v { 1721 | DynamicValue::List(id) => self.special_storage.decrement_ref(id)?, 1722 | DynamicValue::Text(id) => self.special_storage.decrement_ref(id)?, 1723 | _ => {} 1724 | } 1725 | Err(e) => return Err(e), 1726 | } 1727 | } 1728 | } 1729 | 1730 | Ok(ExecutionStatus::Normal) 1731 | } 1732 | } 1733 | 1734 | #[derive(Clone, Debug)] 1735 | pub enum Instruction { 1736 | PrintMathB, 1737 | PrintMathBDebug, 1738 | PrintNewLine, 1739 | FlushStdout, 1740 | Quit, 1741 | Compare, 1742 | Return, 1743 | EndConditionalBlock, 1744 | ExecuteIf(ComparisionRequest), 1745 | MakeNewFrame(usize), 1746 | SetLastFrameReady, 1747 | // For use when pushing arguments for a function. Check if the value on the top of the main stack 1748 | // has a compatible type 1749 | AssertMathBCompatible(TypeKind), 1750 | // Get a line of input and put it at the top of the main stack 1751 | ReadInput, 1752 | // Turn the main stack top into string 1753 | ConvertToString, 1754 | // Turn the main stack top into num 1755 | ConvertToNum, 1756 | // Turn the main stack top into int 1757 | ConvertToInt, 1758 | PushValMathA(RawValue), 1759 | PushValMathB(RawValue), 1760 | PushIntermediateToA, 1761 | PushIntermediateToB, 1762 | PushMathBToSeconday, 1763 | ClearSecondary, 1764 | /// Read a global var to the intermediary register 1765 | ReadGlobalVarFrom(usize), 1766 | /// When writing, values are read from the math b register 1767 | WriteGlobalVarTo(usize), 1768 | ReadVarFrom(usize), 1769 | WriteVarTo(usize), 1770 | WriteVarToLast(usize), 1771 | SwapMath, 1772 | ClearMath, 1773 | Add, 1774 | Mul, 1775 | Div, 1776 | Sub, 1777 | /// Saves the current PC so when the loop ends it can return to it's beginning 1778 | AddLoopLabel, 1779 | /// Return to a previous saved loop label 1780 | RestoreLoopLabel, 1781 | /// Remove a previously saved label 1782 | PopLoopLabel, 1783 | /// Retrieve the increment value from MathB and write it on every Restore to the specified address 1784 | RegisterIncrementOnRestore(usize), 1785 | /// Set the register to denote this is the first operation on the expression 1786 | SetFirstExpressionOperation, 1787 | /// Create a new list and put the result at MathB 1788 | MakeNewList, 1789 | /// Index a list with the ID from the intermediate register and the index from MathB, and put the result in MathB 1790 | IndexList, 1791 | /// Add the result in MathB to the list in the intermediate register, using the index at the secondary register 1792 | /// if the secondary register is Null, the element is placed on the back of the list 1793 | AddToListAtIndex, 1794 | /// Remove the element at the index located in MathB from the list in the intermediate register 1795 | RemoveFromListAtIndex, 1796 | /// Query the list from the intermediate address and write its size to the MathB 1797 | QueryListSize, 1798 | /// Call a plugin function with a number of arguments to pop from the stack 1799 | CallPlugin(usize, usize), 1800 | /// Push the value in MathB to the Plugin Argument stack 1801 | PushMathBPluginArgument, 1802 | /// Increase the skipping level 1803 | IncreaseSkippingLevel, 1804 | /// Halt the execution 1805 | Halt, 1806 | /// Try decrementing the ref count of the object in the specified location in the current frame (if special item) 1807 | TryDecrementRefAt(usize), 1808 | } 1809 | --------------------------------------------------------------------------------