def _find_digit(inter: InterpretContext) -> Optional[Token]: lok = copy.deepcopy(inter.char_feed.loc) cur = inter.char_feed.current() if DIGIT.match(cur): inter.char_feed.pop() # we only get the first digit, interpreter handles the number return Token(d_Grammar.DIGIT, lok, cur)
def _run_func(inter: InterpretContext, func: d_Func) -> Token: try: if func.is_built_in: if func.name == "getConfig": _handle_get_config(inter, func) else: func.py_func(func) elif func.lang is b_Ditlang: interpret(func) else: if not func.code: raise ReturnController(d_Thing.get_null_thing(), func, func.call_loc) _job_loop(GuestDaemonJob(JobType.CALL_FUNC, func)) except d_CodeError as err: err.loc = func.call_loc # err.set_origin( # inter.body.path, func.call_loc, inter.char_feed.get_line(func.call_loc) # ) raise err except d_DitError as err: err.add_trace(func.path, func.call_loc, func.name) raise err except ReturnController as ret: if func.lang is not b_Ditlang: job = GuestDaemonJob(JobType.RETURN_KEYWORD, func) run_job(job) return ret.token except d_TypeMismatchError as mis: raise NotImplementedError else: if func.return_ and func.return_ != d_Grammar.VOID: raise d_SyntaxError(f"{func.pub_name()} expected a return", func.call_loc) elif func.name == MAKE: thing = func.find_attr(THIS) if not thing: raise NotImplementedError return Token(d_Grammar.VALUE_INST, func.call_loc, thing=thing) else: # func ended without 'return' keyword return Token(d_Grammar.NULL, func.call_loc)
def _find_single_chars(inter: InterpretContext) -> Optional[Token]: cur = inter.char_feed.current() lok = copy.deepcopy(inter.char_feed.loc) for d_Grammar in SINGLES: if cur == d_Grammar.value: # WET, appears in _find_double_chars if inter.char_feed.eof(): inter.eof = True else: inter.char_feed.pop() return Token(d_Grammar, lok) return None
def _find_words(inter: InterpretContext, find_word: bool) -> Optional[Token]: token_loc = copy.deepcopy(inter.char_feed.loc) word = _get_word(inter) if word: # Keywords first for grammar in KEYWORDS: if word == grammar.value: return Token(grammar, token_loc) for built_in in BUILT_INS: if word == built_in.name: return Token(d_Grammar.VALUE_FUNC, token_loc, thing=built_in) # Used by var.class.attr expressions # They find the word themselves. if find_word is False: return Token(d_Grammar.WORD, token_loc, word=word) # Most names attr = inter.body.find_attr(word, scope_mode=True) if attr: return Token(attr.grammar, token_loc, thing=attr) else: return Token(d_Grammar.NEW_NAME, token_loc, word=word) else: return None
def _find_double_chars(inter: InterpretContext) -> Optional[Token]: if inter.char_feed.eof(): # Can't be double if we only have 1 char return None cur = inter.char_feed.current() + inter.char_feed.peek() lok = copy.deepcopy(inter.char_feed.loc) for d_Grammar in DOUBLES: if cur == d_Grammar.value: inter.char_feed.pop() # pop first char in double if inter.char_feed.eof(): inter.eof = True else: inter.char_feed.pop() # pop the second if it's safe return Token(d_Grammar, lok)
def _handle_anon( inter: InterpretContext, anon_body: d_Body, orig_loc: CodeLocation, lang: Optional[d_Lang] = None, ) -> Optional[d_Body]: if anon_body.name: # traditional statement, stop here if lang and isinstance(anon_body, d_Lang): # a language is being redeclared, must call set_value to # activate priority comparison stuff lang.set_value(anon_body) else: inter.body.attrs[d_Variable(anon_body.name)] = anon_body inter.named_statement = True return None else: # anonymous expression, need to dispatch it inter.anon_tok = Token(anon_body.grammar, orig_loc, thing=anon_body) return _expression_dispatch(inter) # type: ignore
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_eof(inter: InterpretContext) -> Token: inter.eof = True return Token(d_Grammar.EOF, copy.deepcopy(inter.char_feed.loc))