From 66c87043786ca03e1857eb4927dbcf6e64db37d6 Mon Sep 17 00:00:00 2001 From: Umar Marikar Date: Mon, 20 Jan 2020 14:46:21 +0000 Subject: [PATCH] Add `global:put:` primitive to the `System` class. `global:put:` should return value. Add errors for `global:put:`. --- lang_tests/instance_vars2.som | 8 +-- lang_tests/int_class.som | 12 ----- lang_tests/system3.som | 12 ----- lang_tests/system_global.som | 36 ++++++++++++++ .../system_global_invalid_symbol_err.som | 11 +++++ lib/SOM/System.som | 5 +- src/lib/compiler/ast_to_instrs.rs | 26 +++++----- src/lib/compiler/instrs.rs | 1 + src/lib/vm/core.rs | 49 ++++++++++++------- 9 files changed, 100 insertions(+), 60 deletions(-) delete mode 100644 lang_tests/int_class.som delete mode 100644 lang_tests/system3.som create mode 100644 lang_tests/system_global.som create mode 100644 lang_tests/system_global_invalid_symbol_err.som diff --git a/lang_tests/instance_vars2.som b/lang_tests/instance_vars2.som index fbeea5bb..545257ca 100644 --- a/lang_tests/instance_vars2.som +++ b/lang_tests/instance_vars2.som @@ -2,11 +2,11 @@ VM: status: error stderr: - ...line 11, column 11: - ... - Unknown variable 'x' + InvalidSymbol " instance_vars2 = ( - x = (^x) + run = ( + x = 1 + ) ) diff --git a/lang_tests/int_class.som b/lang_tests/int_class.som deleted file mode 100644 index 8e6e54c9..00000000 --- a/lang_tests/int_class.som +++ /dev/null @@ -1,12 +0,0 @@ -" -VM: - status: success - stdout: - Integer -" - -int_class = ( - run = ( - (Integer class) println. - ) -) \ No newline at end of file diff --git a/lang_tests/system3.som b/lang_tests/system3.som deleted file mode 100644 index cbac1356..00000000 --- a/lang_tests/system3.som +++ /dev/null @@ -1,12 +0,0 @@ -" -VM: - status: success - stdout: - true -" - -system2 = ( - run = ( - ((System global: #Integer) == Integer) println. - ) -) diff --git a/lang_tests/system_global.som b/lang_tests/system_global.som new file mode 100644 index 00000000..7c6c7eb4 --- /dev/null +++ b/lang_tests/system_global.som @@ -0,0 +1,36 @@ +" +VM: + status: success + stdout: + true + true + 42 + 42 + String + 21 + 21 + nil + true + false +" + +system_global = ( + run = ( + ((system global: #Integer) == Integer) println. + system global: #Integer put: 42. + ((system global: #Integer) == Integer) println. + Integer println. + (system global: #Integer) println. + system global: #Integer put: 'a'. + Integer class println. + system global: #ab put: 21. + (system global: #ab) println. + ab println. + system global: #nil put: 'a'. + system global: #true put: 'b'. + system global: #false put: 'c'. + nil println. + true println. + false println. + ) +) diff --git a/lang_tests/system_global_invalid_symbol_err.som b/lang_tests/system_global_invalid_symbol_err.som new file mode 100644 index 00000000..cf57efba --- /dev/null +++ b/lang_tests/system_global_invalid_symbol_err.som @@ -0,0 +1,11 @@ +" +VM: + status: error + stderr: InvalidSymbol +" + +system_global_invalid_symbol_err = ( + run = ( + system global: #ab. + ) +) \ No newline at end of file diff --git a/lib/SOM/System.som b/lib/SOM/System.som index 5c52e41f..a546528f 100644 --- a/lib/SOM/System.som +++ b/lib/SOM/System.som @@ -1,5 +1,6 @@ System = ( global: name = primitive - printString: string = primitive - printNewline = primitive + global: name put: value = primitive + printString: string = primitive + printNewline = primitive ) diff --git a/src/lib/compiler/ast_to_instrs.rs b/src/lib/compiler/ast_to_instrs.rs index 6d074f33..38c0643c 100644 --- a/src/lib/compiler/ast_to_instrs.rs +++ b/src/lib/compiler/ast_to_instrs.rs @@ -239,6 +239,7 @@ impl<'a> Compiler<'a> { "class" => Ok(MethodBody::Primitive(Primitive::Class)), "concatenate:" => Ok(MethodBody::Primitive(Primitive::Concatenate)), "global:" => Ok(MethodBody::Primitive(Primitive::Global)), + "global:put:" => Ok(MethodBody::Primitive(Primitive::GlobalPut)), "halt" => Ok(MethodBody::Primitive(Primitive::Halt)), "hashcode" => Ok(MethodBody::Primitive(Primitive::Hashcode)), "inspect" => Ok(MethodBody::Primitive(Primitive::Inspect)), @@ -486,19 +487,20 @@ impl<'a> Compiler<'a> { vm.instrs_push(Instr::VarLookup(depth, var_num)); } } - Err(e) => match self.lexer.lexeme_str(&lexeme) { - "nil" => vm.instrs_push(Instr::Builtin(Builtin::Nil)), - "false" => vm.instrs_push(Instr::Builtin(Builtin::False)), - "system" => vm.instrs_push(Instr::Builtin(Builtin::System)), - "true" => vm.instrs_push(Instr::Builtin(Builtin::True)), - "Integer" => { - vm.instrs_push(Instr::Global(vm.add_symbol("Integer".to_string()))) - } - "System" => { - vm.instrs_push(Instr::Global(vm.add_symbol("System".to_string()))) + Err(_) => { + let lex_string = self.lexer.lexeme_str(&lexeme); + + match lex_string { + "nil" => vm.instrs_push(Instr::Builtin(Builtin::Nil)), + "false" => vm.instrs_push(Instr::Builtin(Builtin::False)), + "true" => vm.instrs_push(Instr::Builtin(Builtin::True)), + _ => { + vm.instrs_push(Instr::Global( + vm.add_symbol(lex_string.to_string()), + )); + } } - _ => return Err(e), - }, + } } Ok(1) } diff --git a/src/lib/compiler/instrs.rs b/src/lib/compiler/instrs.rs index e6d05b1e..e3d6f97f 100644 --- a/src/lib/compiler/instrs.rs +++ b/src/lib/compiler/instrs.rs @@ -38,6 +38,7 @@ pub enum Primitive { DoubleDiv, Equals, Global, + GlobalPut, GreaterThan, GreaterThanEquals, Halt, diff --git a/src/lib/vm/core.rs b/src/lib/vm/core.rs index e4cdeff9..141d6e48 100644 --- a/src/lib/vm/core.rs +++ b/src/lib/vm/core.rs @@ -44,6 +44,8 @@ pub enum VMError { expected: ObjType, got: ObjType, }, + /// Tried to access a global before it being initialised. + InvalidSymbol, /// Tried to do a shl or shr with a value below zero. NegativeShift, /// A specialised version of TypeError, because SOM has more than one number type (and casts @@ -169,7 +171,6 @@ impl VM { reverse_symbols: UnsafeCell::new(HashMap::new()), frames: UnsafeCell::new(Vec::new()), }; - // The very delicate phase. // // Nothing in this phase must store references to the nil object or any classes earlier @@ -193,6 +194,10 @@ impl VM { vm.sym_cls = vm.init_builtin_class("Symbol", false); vm.system_cls = vm.init_builtin_class("System", false); vm.true_cls = vm.init_builtin_class("True", false); + unsafe { &mut *vm.globals.get() }.insert( + vm.add_symbol("system".to_string()), + Inst::new(&vm, vm.system_cls.clone()), + ); vm.false_ = Inst::new(&vm, vm.false_cls.clone()); vm.system = Inst::new(&vm, vm.system_cls.clone()); vm.true_ = Inst::new(&vm, vm.true_cls.clone()); @@ -231,11 +236,9 @@ impl VM { let val = self.compile(&path, inst_vars_allowed); let idx = self.add_symbol(name.to_string()); - let globals = unsafe { &mut *self.globals.get() }; - - if !globals.get(&idx).is_some() { - globals.insert(idx, Inst::new(self, val.clone())); - } + unsafe { &mut *self.globals.get() } + .entry(idx) + .or_insert(val.clone()); val } @@ -339,12 +342,11 @@ impl VM { } Instr::Global(symbol_off) => { debug_assert!(unsafe { &*self.symbols.get() }.len() > symbol_off); - unsafe { &mut *self.stack.get() }.push( - unsafe { &mut *self.globals.get() } - .get(&symbol_off) - .unwrap_or_else(|| panic!("Could not find global.")) - .clone(), - ); + if let Some(global) = unsafe { &mut *self.globals.get() }.get(&symbol_off) { + unsafe { &mut *self.stack.get() }.push(global.clone()); + } else { + return SendReturn::Err(Box::new(VMError::InvalidSymbol)); + } pc += 1; } Instr::InstVarLookup(n) => { @@ -500,17 +502,28 @@ impl VM { SendReturn::Val } Primitive::Global => { - let v = unsafe { &mut *self.stack.get() }.pop(); - let reverse_symbols = unsafe { &mut *self.reverse_symbols.get() }; - let globals = unsafe { &mut *self.globals.get() }; - let as_string: &String_ = stry!(v.downcast(self)); + let name = unsafe { &mut *self.stack.get() }.pop(); + let as_string: &String_ = stry!(name.downcast(self)); let s = as_string.as_str(); - if let Some(i) = reverse_symbols.get(s) { - if let Some(val) = globals.get(&i) { + if let Some(i) = unsafe { &mut *self.reverse_symbols.get() }.get(s) { + if let Some(val) = unsafe { &mut *self.globals.get() }.get(&i) { unsafe { &mut *self.stack.get() }.push(val.clone()); + return SendReturn::Val; } } + SendReturn::Err(Box::new(VMError::InvalidSymbol)) + } + Primitive::GlobalPut => { + let value = unsafe { &mut *self.stack.get() }.pop(); + let name = unsafe { &mut *self.stack.get() }.pop(); + let as_string: &String_ = stry!(name.downcast(self)); + let s = as_string.as_str(); + + if let Some(i) = unsafe { &mut *self.reverse_symbols.get() }.get(s) { + unsafe { &mut *self.globals.get() }.insert(*i, value.clone()); + unsafe { &mut *self.stack.get() }.push(value); + } SendReturn::Val } Primitive::GreaterThan => {