def make_word_context(word_name: Op_name, op_def: Operation_def, in_seq: Sequence["Type"] = [], out_seq: Sequence["Type"] = []) -> None: sig = TypeSignature(in_seq=[StackObject(stype=x) for x in in_seq], out_seq=[StackObject(stype=x) for x in out_seq]) Type.add_op(Operation(word_name, op_def, sig=sig), sig.stack_in)
def test_op_with_type_multi_input_multi_output_signature(self) -> None: stack = Stack() cont = Continuation(stack) cont.stack.push(StackObject(stype=TTest, value="ttest")) cont.stack.push(StackObject(stype=TParm1, value="tparm")) cont.stack.push(StackObject(stype=TParm1, value="tparm")) make_word_context("test", lambda cont: 42, [TTest, TParm1, TParm1], [TTest, TParm1]) print_words() op, found = Type.op("test", cont) #, "Test") assert found assert op.sig == TypeSignature([ StackObject(stype=TTest), StackObject(stype=TParm1), StackObject(stype=TParm1) ], [StackObject(stype=TTest), StackObject(stype=TParm1)]) op( cont ) # Do this so the lambda doesn't get counted as a missed branch in our code coverage. op, found = Type.op("not found", cont) assert not found
def test_match_in(self) -> None: empty_sig = TypeSignature([], []) s = Stack() assert empty_sig.match_in(s) s.push(StackObject(stype=TParm1)) sig = TypeSignature([StackObject(stype=TParm1)], []) # We can do this twice because it doesn't consume the stack. assert sig.match_in(s) assert sig.match_in(s) s.push(StackObject(stype=TTest)) assert sig.match_in(s) == False
def test_find_ctor(self) -> None: l = [StackObject(stype=TParm1)] assert Type.find_ctor("Test", l).the_op == TOp # Execute the lambda so we get full code coverage. assert TOp("fake_stack") == "fake_stack" l = [StackObject(stype=TAny)] assert Type.find_ctor("Test", l).the_op == TOp l = [StackObject(stype=TTest)] assert Type.find_ctor("Test", l) == None l = [] assert Type.find_ctor("Test", l) == None
def op_less_than(c: AF_Continuation) -> None: sobj1 = optionally_infer_type_from_atom(c) sobj2 = c.stack.pop() c.log.debug( "is %s (%s) < %s (%s)?" % (sobj2.value, type(sobj2.value), sobj1.value, type(sobj1.value))) c.stack.push(StackObject(value=(sobj2.value < sobj1.value), stype=TBool))
def test_op_with_wrong_type_signature(self) -> None: stack = Stack() stack.push(StackObject(stype=TTest, value="tparm")) make_word_context("test", op_print, [TParm1]) with self.assertRaises(Exception): Type.op("test", stack)
def make_atom(c: AF_Continuation) -> None: c.log.debug("make_atom c.symbol = '%s'" % c.symbol) if c.symbol is None: c.symbol = Symbol("Unknown", Location()) text = c.symbol.s_id if text.startswith('"') and text.endswith('"'): # Strip off the quotes now. Strings are atoms for now. text = text[1:-1] c.stack.push(StackObject(value=text, stype=TAtom))
def test_compile_multi_input_multi_output(self) -> None: code = """ multiinput : Bool Int Int Int -> Int ; + == == . False bool 1 int 1 int 1 int """ stack = Stack() cont = Continuation(stack) cont = cont.execute(interpret(cont, io.StringIO(code))) op, found = Type.op("multiinput", cont ) #, "Test") assert found assert op.sig == TypeSignature([StackObject(stype=TBool),StackObject(stype=TInt),StackObject(stype=TInt),StackObject(stype=TInt)], [StackObject(stype=TInt)]) op, found = Type.op("not found", cont) assert not found
def setUp(self) -> None: self.stack = Stack() self.cont = Continuation(self.stack) self.save_types = deepcopy(Type.types) self.save_ctors = deepcopy(Type.ctors) # Clear up all the types. the_types = ["Any", "CodeCompile", "Parm1", "Test"] for t in the_types: x = Type(t) Type.register_ctor("Test", Operation('nop', TOp), [StackObject(stype=TParm1)])
def register_ctor(name: Type_name, op: Operation, input_sig: List["StackObject"]) -> None: # Ctors only have TypeSignatures that return their own Type. # Register the ctor in the Global dictionary. op.sig = TypeSignature(input_sig, [StackObject(stype=Type(name))]) # Type.add_op(op) # Append this ctor to our list of valid ctors. op_map = Type.ctors.get(name, None) assert op_map is not None, ( "No ctor map for type %s found.\n\tCtors exist for the following types: %s." % (name, Type.ctors.keys())) op_map.append((input_sig, op))
def find_op(name: Op_name, cont: AF_Continuation, type_name: Type_name) -> Tuple[Operation, bool]: type_def: TypeDefinition = Type.types[ type_name] # (type_name,Type.types["Any"]) cont.log.debug("Searching for op:'%s' in type: '%s'." % (name, type_name)) assert type_def is not None, "No type '%s' found. We have: %s" % ( type, Type.types.keys()) name_found = False sigs_found: List[TypeSignature] = [] if type_def: op_list = type_def.ops_list cont.log.debug("\top_list = %s" % [op for op in op_list]) for op in op_list: if op.name == name: name_found = True sigs_found.append(op.sig) # Now try to match the input stack... try: if op.check_stack_effect( cont.stack ): # TODO - are we doing the right thing with this return types? cont.log.debug("Found! Returning %s, %s, %s" % (op, op.sig, True)) return op, True except SigValueTypeMismatchException: # We found the name but not the right value/type sig. Keep looking. pass # Not found. if name_found: # Is this what we want to do? # This will happen if names match but stacks don't. cont.log.debug( "Continuation (stack = %s) doesn't match Op '%s' with available signatures: %s." % (cont.stack, name, [s.stack_in for s in sigs_found])) raise Exception( "Continuation (stack = %s) doesn't match Op '%s' with available signatures: %s." % (cont.stack, name, [s.stack_in for s in sigs_found])) cont.log.debug("Not found!") # Default operation is to treat the symbol as an Atom and put it on the stack. return Operation("make_atom", make_atom, sig=TypeSignature([], [StackObject(stype=TAtom)])), False
def test_op_dup(self) -> None: @dataclass class DupTest: val: str self.c.stack.push(StackObject(value=DupTest("Something"), stype=TAtom)) op_dup(self.c) op_dup(self.c) item1 = self.c.stack.pop() self.c.stack.tos().value.val = "SomethingElse" assert item1.value.val == "Something" item2 = self.c.stack.pop() assert item2.value.val == "SomethingElse" assert item1 != item2 item3 = self.c.stack.pop() assert item3.value.val == "Something" assert item2 != item3 assert item1 == item3
def op_bool(c: AF_Continuation) -> None: stack_object = c.stack.pop() #print("op_bool stack_object = %s" % stack_object) result = StackObject(value=None, stype=TBool) if stack_object.stype == TBool: #print ("Got a Bool") result.value = stack_object.value if stack_object.stype == TAtom: #print ("Got an Atom") if stack_object.value == "True": #print ("Found a True Atom") result.value = True if stack_object.value == "False": #print ("Found a False Atom") result.value = False assert result.value is not None, "%s is not a valid Boolean value." % stack_object.value c.stack.push(result)
def test_curry_match_and_execute(self) -> None: words = [ Operation("test", op_gen(StackObject(stype=TInt, value=99), 1), sig=TypeSignature([self.zero_pattern], [self.int_pattern])) ] curry, sig = match_and_execute_compiled_word(self.cont, words) self.cont.stack.push(StackObject(stype=TInt, value=0)) curry(self.cont) assert self.cont.stack.pop().value == 99 self.cont.stack.push(StackObject(stype=TInt, value=1)) with self.assertRaises(Exception) as x: curry(self.cont) words.append( Operation("test", op_gen(StackObject(stype=TInt, value=101), 1), sig=TypeSignature([self.one_pattern], [self.int_pattern]))) curry(self.cont) assert self.cont.stack.pop().value == 101 words.append( Operation("test", op_gen(StackObject(stype=TInt, value=76), 1), sig=TypeSignature([self.any_pattern], [self.int_pattern]))) self.cont.stack.push(StackObject(stype=TInt, value=0)) self.cont.stack.push(StackObject(stype=TInt, value=42)) curry(self.cont) assert self.cont.stack.pop().value == 76 curry(self.cont) assert self.cont.stack.pop().value == 99
def setUp(self) -> None: self.stack = Stack() self.cont = Continuation(self.stack) self.save_types = deepcopy(Type.types) self.save_ctors = deepcopy(Type.ctors) self.zero_pattern = StackObject(stype=TInt, value=0) self.one_pattern = StackObject(stype=TInt, value=1) self.any_pattern = StackObject(stype=TAny) self.true_pattern = StackObject(stype=TBool, value=True) self.false_pattern = StackObject(stype=TBool, value=False) self.int_pattern = StackObject(stype=TInt) op_debug(self.cont) op_on(self.cont)
def test_op_drop(self) -> None: self.s.push(StackObject(stype=TAtom, value="test")) op_drop(self.c) assert self.c.stack.depth() == 0
def op_equals(c: AF_Continuation) -> None: sobj1 = optionally_infer_type_from_atom(c) # Now we pop off whatever is the ultimate object that's # possibly been inferred. sobj2 = c.stack.pop() c.stack.push(StackObject(value=(sobj1 == sobj2), stype=TBool))
def op_greater_than_or_equal_to(c: AF_Continuation) -> None: sobj1 = optionally_infer_type_from_atom(c) sobj2 = c.stack.pop() c.stack.push(StackObject(value=(sobj2.value >= sobj1.value), stype=TBool))
def make_ratom(c: AF_Continuation) -> None: c.rstack.push(StackObject(value=c.symbol.s_id, stype=TAtom))
if stack_object.stype == TAtom: #print ("Got an Atom") if stack_object.value == "True": #print ("Found a True Atom") result.value = True if stack_object.value == "False": #print ("Found a False Atom") result.value = False assert result.value is not None, "%s is not a valid Boolean value." % stack_object.value c.stack.push(result) Type.register_ctor('Bool', Operation('bool', op_bool), [StackObject(stype=TAtom)]) Type.register_ctor('Bool', Operation('bool', op_bool), [StackObject(stype=TBool)]) #Type.register_ctor('Bool',Operation('bool',op_bool),[StackObject(stype=TAny)]) # HACK BDM TODO NASTY! ### TODO : if issue 4 ( https://github.com/ActorForth/ActorForth/issues/4 ) ### is working properly then we shouldn't need this, right? make_word_context('bool', op_bool, [TAtom], [TBool]) make_word_context('bool', op_bool, [TBool], [TBool]) # TODO : issue #17 wait for created gerneralize type infer def optionally_infer_type_from_atom(c: AF_Continuation) -> StackObject: #op_debug(c) #op_on(c)