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/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 bacff466..a546528f 100644 --- a/lib/SOM/System.som +++ b/lib/SOM/System.som @@ -1,4 +1,6 @@ System = ( - printString: string = primitive - printNewline = primitive + global: name = 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 7ab8a94d..38c0643c 100644 --- a/src/lib/compiler/ast_to_instrs.rs +++ b/src/lib/compiler/ast_to_instrs.rs @@ -238,6 +238,8 @@ impl<'a> Compiler<'a> { "asSymbol" => Ok(MethodBody::Primitive(Primitive::AsSymbol)), "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)), @@ -485,13 +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)), - _ => return Err(e), - }, + 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()), + )); + } + } + } } Ok(1) } diff --git a/src/lib/compiler/instrs.rs b/src/lib/compiler/instrs.rs index 57e3a517..e3d6f97f 100644 --- a/src/lib/compiler/instrs.rs +++ b/src/lib/compiler/instrs.rs @@ -2,6 +2,7 @@ pub enum Instr { Block(usize), Builtin(Builtin), + Global(usize), ClosureReturn(usize), Double(f64), InstVarLookup(usize), @@ -36,6 +37,8 @@ pub enum Primitive { Div, DoubleDiv, Equals, + Global, + GlobalPut, GreaterThan, GreaterThanEquals, Halt, diff --git a/src/lib/vm/core.rs b/src/lib/vm/core.rs index aa28c5cf..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 @@ -111,6 +113,7 @@ pub struct VM { pub system: Val, pub true_: Val, blockinfos: UnsafeCell>, + globals: UnsafeCell>, inline_caches: UnsafeCell)>>>, instrs: UnsafeCell>, sends: UnsafeCell>, @@ -156,6 +159,7 @@ impl VM { system: Val::illegal(), true_: Val::illegal(), blockinfos: UnsafeCell::new(Vec::new()), + globals: UnsafeCell::new(HashMap::new()), inline_caches: UnsafeCell::new(Vec::new()), instrs: UnsafeCell::new(Vec::new()), sends: UnsafeCell::new(Vec::new()), @@ -167,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 @@ -191,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()); @@ -226,7 +233,14 @@ impl VM { let path = self .find_class(name) .unwrap_or_else(|_| panic!("Can't find builtin class '{}'", name)); - self.compile(&path, inst_vars_allowed) + + let val = self.compile(&path, inst_vars_allowed); + let idx = self.add_symbol(name.to_string()); + unsafe { &mut *self.globals.get() } + .entry(idx) + .or_insert(val.clone()); + + val } /// Inform the user of the error string `error` and then exit. @@ -326,6 +340,15 @@ impl VM { unsafe { &mut *self.stack.get() }.push(Double::new(self, i)); pc += 1; } + Instr::Global(symbol_off) => { + debug_assert!(unsafe { &*self.symbols.get() }.len() > symbol_off); + 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) => { let inst: &Inst = rcv.downcast(self).unwrap(); unsafe { &mut *self.stack.get() }.push(inst.inst_var_lookup(n)); @@ -478,6 +501,31 @@ impl VM { )); SendReturn::Val } + Primitive::Global => { + 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) { + 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 => { unsafe { &mut *self.stack.get() }.push(stry!( rcv.greater_than(self, unsafe { &mut *self.stack.get() }.pop()) @@ -853,6 +901,7 @@ impl VM { system: Val::illegal(), true_: Val::illegal(), blockinfos: UnsafeCell::new(Vec::new()), + globals: UnsafeCell::new(HashMap::new()), inline_caches: UnsafeCell::new(Vec::new()), instrs: UnsafeCell::new(Vec::new()), sends: UnsafeCell::new(Vec::new()),