def _equals(inter: InterpretContext, equal_loc: CodeLocation) -> None: orig_loc = copy.deepcopy(inter.next_tok.loc) if inter.anon_tok or inter.call_tok: # prevent assignment to anonymous tokens. raise NotImplementedError if inter.dec.type_: assignee = None else: assignee = inter.curr_tok.thing inter.advance_tokens() inter.equaling = True value = _expression_dispatch(inter) inter.equaling = False if not value: if inter.named_statement: # Prevent assignment of non-anonymous statements. # Class anonName = class RealName {||} raise d_SyntaxError( "A named declaration cannot be used for assignment", orig_loc) else: raise d_CriticalError( "No value for _expression_dispatch in _equals") if assignee: assignee.set_value(value) else: try: _add_attr_wrap(inter, value=value) except d_TypeMismatchError as err: err.loc = equal_loc raise
def _check_for_duplicates(thing: d_Container, name: str) -> None: if isinstance(thing, d_Inst): var = thing.compose_prefix(name) else: var = d_Variable(name) if var in thing.attrs: raise d_CriticalError(f"A duplicate attribute was found: '{name}'")
def add_attr(self, dec: Declarable, value: Optional[d_Thing] = None, use_ref: bool = False) -> d_Thing: ref = None if dec.name is None: raise d_CriticalError("A declarable had no name") _check_for_duplicates(self, dec.name) if value: res = check_value(value, dec) if res: raise d_TypeMismatchError( f"Cannot assign {res.actual} to {res.expected}{res.extra}") if dec.type_ == d_Grammar.PRIMITIVE_THING: value.can_be_anything = True if use_ref: # Use a ref to hide the original name without changing it # Currently only used for function parameters afaik ref = d_Ref(dec.name, value) else: value.name = dec.name else: value = _type_to_obj(dec) fin_val = ref or value fin_var = d_Variable(fin_val.name) if isinstance(self, d_Inst): fin_var = self.compose_prefix(fin_val.name) self.attrs[fin_var] = fin_val return value
def set_value(self, new_value: d_Thing) -> None: self.is_null = new_value.is_null if isinstance(new_value, d_List): # listOf Str = ['1', '2']; self.list_ = new_value.list_ _check_list_type(self) elif self.can_be_anything: super().set_value(new_value) elif isinstance(new_value, d_Thing): # type: ignore raise d_TypeMismatchError( f"Cannot assign {new_value.public_type} to List") else: raise d_CriticalError("Unrecognized type for list assignment")
def _type_to_obj(dec: Declarable) -> d_Thing: thing: d_Thing = None # type: ignore if not dec.type_: raise d_CriticalError("A declarable had no type") elif isinstance(dec.type_, d_Class): thing = d_Inst() thing.parent = dec.type_ elif dec.listof: thing = d_List() # this prim_to_value might fail with classes thing.contained_type = prim_to_value(dec.type_) # type: ignore elif dec.type_ == d_Grammar.PRIMITIVE_THING: thing = d_Thing() thing.can_be_anything = True else: # equivalent to thing = d_Str(), just with the Object Dispatch thing = OBJECT_DISPATCH[dec.type_]() if thing: thing.name = dec.name return thing else: raise d_CriticalError("Unrecognized type for declaration")
def set_value(self, new_value: d_Thing) -> None: # alter own class to *become* the type it is assigned to. # note that 'can_be_anything' is still True # and public_type is still "Thing" if isinstance(new_value, d_Thing): # type: ignore self.__class__ = new_value.__class__ self.grammar = new_value.grammar self.public_type = new_value.public_type else: raise d_CriticalError("Unrecognized type for thing assignment") if not type(new_value) == d_Thing: # After altering class, set the actual value using subclass set_value self.set_value(new_value)
def _generate_origin(err: d_DitError, inter: InterpretContext, loc: Optional[CodeLocation] = None) -> None: if not err.loc: # If the code is total garbage, the next token may not be assigned. # In that case, we default to wherever the char_feed happens to be. if inter.next_tok: err.loc = inter.next_tok.loc else: err.loc = inter.char_feed.loc if inter.body.path is None: raise d_CriticalError("A body had no path during exception") code = inter.char_feed.get_line(err.loc) err.set_origin(inter.body.path, code)
def find_attr(self, name: str, scope_mode: bool = False) -> Optional[d_Thing]: var = d_Variable(name) if isinstance(self, d_Inst): var = self.compose_prefix(name) if scope_mode: if not isinstance(self, d_Body): raise d_CriticalError("A Container was given for scope mode") # We need to check for this name in upper scopes # Str someGlobal = 'cat'; # class someClass {| Str someInternal = someGlobal; |} return _find_attr_in_scope(var, self) else: # We're dotting, so only 'self' counts, no upper scopes. # We also need to check for inherited parent classes # someInst.someMember = ... return _find_attr_in_self(var, self)
def _paren_left(inter: InterpretContext) -> Optional[d_Thing]: func = (inter.anon_tok or inter.call_tok or inter.curr_tok).thing if isinstance(func, d_Class): # This means we must be instantiating, and need the Make func # Number num = Number('3'); func = _make(inter) elif not isinstance(func, d_Func): raise d_CriticalError(f"Expected function, got {func.public_type}") func.new_call() # handles recursive attribute stack stored_inst = None if inter.dotted_inst and not inter.equaling: # We are activating a function of this instance, so the func needs 'this' # Subject to change when static functions are implemented # num.inc(); func.add_attr( Declarable(inter.dotted_inst.parent, THIS), inter.dotted_inst, use_ref=True, ) stored_inst = inter.dotted_inst inter.dotted_inst = None # type: ignore _get_func_args(inter, func) if not func.code and func.lang is not b_Ditlang: preprocess(func) inter.call_tok = _run_func(inter, func) func.end_call() if stored_inst: stored_inst.pop_func_sep() if inter.call_tok.grammar == d_Grammar.NULL: return _terminal(inter) else: return _parenable(inter)
def _dot(inter: InterpretContext) -> Token: inter.advance_tokens(False) # We want to manage the next word ourselves if inter.next_tok.grammar != d_Grammar.WORD: raise d_SyntaxError(f"'{inter.next_tok.grammar}' is not dotable") # Allows dotting of anonymous tokens and function calls. target = (inter.anon_tok or inter.call_tok or inter.prev_tok).thing if isinstance(target, d_Inst): # We need to prepare in case the instance has inherited parents target.clear_prefix_to_func() inter.dotted_inst = target elif not isinstance(target, d_Container): raise d_CriticalError(f"Expected container, got {target.public_type}") result = target.find_attr(inter.next_tok.word) if not result and inter.dotted_inst: # this.B.attribute # We are doing explicit name disambiguation, looking in parent B instead of A. # B obviously doesn't have the attribute, the instance does. # So we look again in the instance. result = inter.dotted_inst.find_attr(inter.next_tok.word) if result: # The dot had a known variable, which we just need to return if isinstance(result, d_Func) and inter.dotted_inst: # this.func() # if `func` is an inherited function, we need to remember that we # called it so the prefixes are set up correctly. inter.dotted_inst.add_func_sep() return Token(result.grammar, copy.deepcopy(inter.next_tok.loc), thing=result) else: # The name was not found in the dotted body, so its a new name. # This means we are declaring a new var in the dotted body. # AKA Monkey patching inter.next_tok.grammar = d_Grammar.NEW_NAME inter.dotted_body = target # Save for assignment return inter.next_tok
def handle_filepath(self) -> None: if self.view is not None: return if self.path is None: raise d_CriticalError("A dit had no path") if self.path.startswith("https://") or self.path.startswith("http://"): try: contents = urlopen(self.path).read().decode() except (HTTPError, URLError) as error: raise d_FileError(f"Import failed, {error}") else: try: with open(self.path) as file_object: contents = file_object.read() except FileNotFoundError: raise d_FileError("Import failed, file not found") except PermissionError: raise d_FileError("Import failed, permission denied") except IsADirectoryError: raise d_FileError("Import failed, not a directory") self.view = memoryview(contents.encode())
def _service_client(key: selectors.SelectorKey, mask: int): """Send or receive message from a guest lang.""" global JOB conn: socket.socket = key.fileobj # type: ignore client = _get_client(key.data) if client is None: return if JOB and mask & selectors.EVENT_READ: recv_data = conn.recv(1024) if recv_data: data = _decode(recv_data) if data["type"] == JobType.HEART.value: pass elif data["type"] == JobType.CRASH.value: JOB.crash = d_CodeError(data["result"], JOB.func.lang.name, JOB.func.guest_func_path) elif data["type"] == JobType.EXE_DITLANG.value: JOB.result = data["result"] JOB.type_ = JobType.EXE_DITLANG elif data["type"] == JobType.FINISH_FUNC.value: JOB.type_ = JobType.FINISH_FUNC JOB.active = False else: raise d_CriticalError("Unrecognized job type") elif mask & selectors.EVENT_WRITE: if (JOB and not JOB.active and JOB.func.lang == client.lang and JOB.type_ in ( JobType.CALL_FUNC, JobType.DITLANG_CALLBACK, JobType.RETURN_KEYWORD, JobType.CLOSE, )): global PORT mes = JOB.get_json() conn.sendall(mes) JOB.active = True
def _trigger_eof_err(inter: InterpretContext) -> NoReturn: inter.char_feed.pop() raise d_CriticalError("EOF reached, but failed to trigger")
def is_ready(self) -> bool: if self.view is None: raise d_CriticalError("A body had no view during readying") return len(self.view) > 0
def get_data(self) -> None: if self.is_null: return None else: raise d_CriticalError("Thing get_data called on non-null thing.")
def __str__(self): if self.is_null: return d_Grammar.NULL.value else: raise d_CriticalError("Thing __str__ called on non-null thing.")