├── .gitignore ├── LICENSE ├── README.MD ├── great.he ├── helang ├── __init__.py ├── __main__.py ├── enum_method.py ├── exceptions.py ├── he_ast.py ├── lexer.py ├── parser.py ├── tokens.py └── u8.py └── tests ├── test_ast.py ├── test_lexer.py └── test_parser.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | helang.iml 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Kifuan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # HeLang:何语言 2 | 3 | Next-Generation **Cyber** Programming Language from Li Tang. 4 | 5 | 引个流先:https://www.bilibili.com/video/BV1XW4y1h79A/ 6 | 7 | ## 介绍 8 | 9 | 次世代赛博编程语言,诞生于**E-SMOKER**之乡:赛博理塘。 10 | 11 | 本项目是由自己会打字的5G键盘,花了108赛博分钟,在AirDesk上配合AirPods编写的。 12 | 13 | 实在是太酷了,很符合我对未来生活的想象,科技并带着趣味。 14 | 15 | 注:如果以**普通时间单位**(Basic Unit of Plain Time, [**BUPT**](https://baike.baidu.com/item/%E5%8C%97%E4%BA%AC%E9%82%AE%E7%94%B5%E5%A4%A7%E5%AD%A6/139535?from=kg))作为标准单位,本项目开发时长为`1! + 5! + 5! + 5! = 361 `分钟。 16 | 17 | 注2:**BUPT** 在赛博世界还可以写为 Beijing University of Posts and Telecommunications,北京邮电大学(声明:我对本学府无恶意,我认为这是一所优秀的学校,我只是对某个人)。 18 | 19 | ## 语法 20 | 21 | **Saint He** 曾说,一切类型均为`u8`,是什么意思呢?这个词倒过来就是`8u`,看来圣人也喜欢玩贴吧。 22 | 23 | 如你所见,我们用**bitwise or**,即`|`代替了传统数组的符号。**都什么年代了还在写传统数组**? 24 | 25 | ```c 26 | u8 array = 1 | 2 | 3; 27 | ``` 28 | 29 | **Saint He** 曾说:`whichKey - 1` ,所以我们数组的下标需要从 `1` 开始。 30 | 31 | ```c 32 | print array[1]; 33 | // 1 34 | ``` 35 | 36 | 为了符合最新的技术,我们同样支持多下标操作,所以你再也不用写 `for` 循环了。 37 | 38 | ```c 39 | array[1 | 2] = 0; 40 | print array; 41 | // 0 | 0 | 3 42 | ``` 43 | 44 | 同样,我们还提供了一种根据数组长度的初始化方式,可惜这还是传统写法。比如下面的代码,可以初始化一个长度为10的数组。 45 | 46 | ```c 47 | u8 array = [10]; 48 | ``` 49 | 50 | 最后,我们结合一下,可以写出下列代码。 51 | 52 | ```c 53 | u8 forceCon = [68]; 54 | 55 | forceCon[1 | 2 | 6 | 7 | 11 | 52 | 57 | 58 | 65] = 10; 56 | 57 | print forceCon; 58 | ``` 59 | 60 | 如此精妙的代码,在地球的人类是无法理解的。我们作为**赛博智能生命体**,也只能给你演示一下日常操作了。 61 | 62 | 对了,还有一个要求,你的注释必须写在行开始部分,因为我直接用 `strip().startswith('//')` 判断。 63 | 64 | 这实在是太酷了,后面我忘了,我也不想翻到文章开头去看。 65 | 66 | ## 总结 67 | 68 | 关注永雏塔菲喵,关注永雏塔菲谢谢喵。 69 | 70 | 关注[猫雷NyaRu_Official](https://space.bilibili.com/697091119)谢谢喵,要吃中国的大米喵。 71 | 72 | ## 附加 73 | 74 | 现在是凌晨两点,我治好了自己的精神内耗。 75 | -------------------------------------------------------------------------------- /great.he: -------------------------------------------------------------------------------- 1 | u8 array = 4 | 6 | 8; 2 | print array[1 | 3]; 3 | // 4 | 8 4 | 5 | u8 forceCon = [68]; 6 | forceCon[1 | 2 | 6 | 7 | 11 | 52 | 57 | 58 | 65] = 10; 7 | print forceCon; 8 | -------------------------------------------------------------------------------- /helang/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAOKnight/helang/aa551fe3015e76a1179c195582277d81454f2292/helang/__init__.py -------------------------------------------------------------------------------- /helang/__main__.py: -------------------------------------------------------------------------------- 1 | from helang.lexer import Lexer 2 | from helang.parser import Parser 3 | 4 | 5 | if __name__ == '__main__': 6 | with open('../great.he', 'r') as f: 7 | content = f.read() 8 | lexer = Lexer(content) 9 | parser = Parser(lexer.lex()) 10 | env = dict() 11 | parser.parse().evaluate(env) 12 | -------------------------------------------------------------------------------- /helang/enum_method.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class Methods: 5 | def __init__(self): 6 | self._methods = dict() 7 | 8 | def bind(self, enum: Enum): 9 | def bind_method(method: callable): 10 | self._methods[enum] = method 11 | return method 12 | return bind_method 13 | 14 | def apply(self, enum: Enum, *args, **kwargs): 15 | return self._methods[enum](*args, **kwargs) 16 | -------------------------------------------------------------------------------- /helang/exceptions.py: -------------------------------------------------------------------------------- 1 | class BadTokenException(Exception): 2 | ... 3 | 4 | 5 | class BadStatementException(Exception): 6 | ... 7 | -------------------------------------------------------------------------------- /helang/he_ast.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | from helang.u8 import U8 3 | 4 | 5 | class AST: 6 | def evaluate(self, env: Dict[str, U8]) -> U8: 7 | raise NotImplemented() 8 | 9 | 10 | class VarDefAST(AST): 11 | def __init__(self, ident: str, val: AST): 12 | self._ident = ident 13 | self._val = val 14 | 15 | def evaluate(self, env: Dict[str, U8]) -> U8: 16 | val = self._val.evaluate(env) 17 | env[self._ident] = val 18 | return U8() 19 | 20 | 21 | class VarExprAST(AST): 22 | def __init__(self, ident: str): 23 | self._ident = ident 24 | 25 | def evaluate(self, env: Dict[str, U8]) -> U8: 26 | return env[self._ident] 27 | 28 | 29 | class EmptyU8InitAST(AST): 30 | def __init__(self, length: int): 31 | self._length = length 32 | 33 | def evaluate(self, env: Dict[str, U8]) -> U8: 34 | return U8([0] * self._length) 35 | 36 | 37 | class OrU8InitAST(AST): 38 | """ 39 | How the King He defines uint8 list: by | operator. 40 | """ 41 | 42 | def __init__(self, first: int, second: Optional['OrU8InitAST'] = None): 43 | self._first = first 44 | self._second = second 45 | 46 | def evaluate(self, env: Dict[str, U8]) -> U8: 47 | if self._second is None: 48 | return U8([self._first]) 49 | second = self._second.evaluate(env).value 50 | elements = [self._first] 51 | elements.extend(second) 52 | return U8(elements) 53 | 54 | 55 | class ListAST(AST): 56 | def __init__(self, asts: List[AST]): 57 | self.asts = asts 58 | 59 | def evaluate(self, env: Dict[str, U8]) -> U8: 60 | last = U8() 61 | for ast in self.asts: 62 | last = ast.evaluate(env) 63 | return last 64 | 65 | 66 | class U8SetAST(AST): 67 | def __init__(self, list_expr: AST, subscript_expr: AST, value_expr: AST): 68 | self._list = list_expr 69 | self._subscript = subscript_expr 70 | self._value = value_expr 71 | 72 | def evaluate(self, env: Dict[str, U8]) -> U8: 73 | lst = self._list.evaluate(env).value 74 | subscripts = self._subscript.evaluate(env).value 75 | val = self._value.evaluate(env).value 76 | # Flat single element list to the element itself. 77 | if len(val) == 1: 78 | val = val[0] 79 | for i in subscripts: 80 | # Saint He likes arrays whose subscript start from 1. 81 | lst[i-1] = val 82 | return U8() 83 | 84 | 85 | class U8GetAST(AST): 86 | def __init__(self, list_expr: AST, subscript_expr: AST): 87 | self._list = list_expr 88 | self._subscript = subscript_expr 89 | 90 | def evaluate(self, env: Dict[str, U8]) -> U8: 91 | lst = self._list.evaluate(env).value 92 | subscripts = self._subscript.evaluate(env).value 93 | # Like the operation of sublist. 94 | # And Saint He likes arrays whose subscript start from 1. 95 | return U8([lst[i-1] for i in range(1, len(lst) + 1) if i in subscripts]) 96 | 97 | 98 | class PrintAST(AST): 99 | def __init__(self, expr: AST): 100 | self._expr = expr 101 | 102 | def evaluate(self, env: Dict[str, U8]) -> U8: 103 | val = self._expr.evaluate(env) 104 | print(str(val)) 105 | return val 106 | -------------------------------------------------------------------------------- /helang/lexer.py: -------------------------------------------------------------------------------- 1 | import enum 2 | import re 3 | 4 | from typing import * 5 | from helang.tokens import Token, TokenKind, SINGLE_CHAR_TOKEN_KINDS 6 | from helang.enum_method import Methods 7 | from helang.exceptions import BadTokenException 8 | 9 | 10 | class LexerState(enum.Enum): 11 | # Waiting for next meaningful character. 12 | WAIT = 1 13 | # Identifiers. 14 | IDENT = 2 15 | # Numbers. 16 | NUMBER = 3 17 | # Increments. 18 | INCREMENT = 4 19 | 20 | 21 | class Lexer: 22 | methods = Methods() 23 | 24 | def __init__(self, content: str): 25 | # Add a whitespace to let the methods do some clean-up. 26 | self._content = ''.join(line for line in content.split('\n') if not line.strip().startswith('//')) + ' ' 27 | self._state = LexerState.WAIT 28 | self._pos = 0 29 | self._cache = '' 30 | 31 | def lex(self) -> List[Token]: 32 | self._pos = 0 33 | tokens = [] 34 | while self._pos < len(self._content): 35 | Lexer.methods.apply(self._state, self, tokens) 36 | return tokens 37 | 38 | @property 39 | def _curr(self): 40 | """ 41 | Current character. 42 | :return: current character. 43 | """ 44 | return self._content[self._pos] 45 | 46 | @methods.bind(LexerState.WAIT) 47 | def _lex_wait(self, tokens: List[Token]): 48 | # Anyway, clear the cache. 49 | self._cache = '' 50 | 51 | if re.match(r'\s', self._curr): 52 | # Matched space, skipping. 53 | self._pos += 1 54 | return 55 | 56 | if re.match(r'\d', self._curr): 57 | # Matched number, changing state to NUMBER. 58 | self._state = LexerState.NUMBER 59 | return 60 | 61 | if re.match(r'[a-zA-Z_$]', self._curr): 62 | # Matched identifier, changing state to IDENT. 63 | self._state = LexerState.IDENT 64 | return 65 | 66 | if self._curr == '+': 67 | # Matched increment operator, changing state to INCREMENT. 68 | self._state = LexerState.INCREMENT 69 | return 70 | 71 | if self._curr in SINGLE_CHAR_TOKEN_KINDS.keys(): 72 | # Matched single char token, adding it to the list. 73 | kind = SINGLE_CHAR_TOKEN_KINDS[self._curr] 74 | tokens.append(Token(self._curr, kind)) 75 | self._pos += 1 76 | return 77 | 78 | raise BadTokenException(self._curr) 79 | 80 | @methods.bind(LexerState.IDENT) 81 | def _lex_ident(self, tokens: List[Token]): 82 | if self._cache != '' and not re.match(r'[A-Za-z0-9_$]', self._curr): 83 | # Current character is not identifier, changing state to WAIT. 84 | if self._cache == 'u8': 85 | tokens.append(Token(self._cache, TokenKind.U8)) 86 | elif self._cache == 'print': 87 | tokens.append(Token(self._cache, TokenKind.PRINT)) 88 | else: 89 | tokens.append(Token(self._cache, TokenKind.IDENT)) 90 | self._state = LexerState.WAIT 91 | return 92 | 93 | self._cache += self._curr 94 | self._pos += 1 95 | 96 | @methods.bind(LexerState.NUMBER) 97 | def _lex_number(self, tokens: List[Token]): 98 | # Not support for floats yet, as the King He hasn't written any floats. 99 | if not re.match(r'\d', self._curr): 100 | # Current character is not number, changing state to WAIT. 101 | tokens.append(Token(self._cache, TokenKind.NUMBER)) 102 | self._state = LexerState.WAIT 103 | return 104 | 105 | self._cache += self._curr 106 | self._pos += 1 107 | 108 | @methods.bind(LexerState.INCREMENT) 109 | def _lex_increment(self, tokens: List[Token]): 110 | if self._cache == '+' and self._curr != '+': 111 | raise BadTokenException('only ++ operator is expected, as the King He has NOT written single +') 112 | 113 | if self._cache == '++': 114 | # Enough + operator, changing state to WAIT. 115 | tokens.append(Token(self._cache, TokenKind.INCREMENT)) 116 | self._state = LexerState.WAIT 117 | return 118 | 119 | self._cache += self._curr 120 | self._pos += 1 121 | -------------------------------------------------------------------------------- /helang/parser.py: -------------------------------------------------------------------------------- 1 | from helang.tokens import Token, TokenKind 2 | from helang.exceptions import BadStatementException 3 | from helang.he_ast import * 4 | from typing import * 5 | 6 | 7 | class Parser: 8 | def __init__(self, tokens: List[Token]): 9 | self._tokens = tokens 10 | self._pos = 0 11 | 12 | def _expect(self, expected_kind: TokenKind, validator: Optional[Callable[[Token], bool]] = None): 13 | if self._pos >= len(self._tokens): 14 | raise BadStatementException('no more tokens') 15 | 16 | token = self._tokens[self._pos] 17 | 18 | if token.kind != expected_kind: 19 | raise BadStatementException(f'expected {expected_kind} at pos {self._pos}, got {token.kind}') 20 | 21 | if validator is not None and not validator(token): 22 | raise BadStatementException(f'failed to pass custom validator at offset {self._pos}') 23 | 24 | self._pos += 1 25 | return token 26 | 27 | def parse(self) -> AST: 28 | root_parsers = [self._root_parse_print, self._root_parse_u8_set, self._root_parse_var_def, self._root_parse_expr] 29 | asts = [] 30 | while self._pos < len(self._tokens): 31 | for parser in root_parsers: 32 | saved_pos = self._pos 33 | try: 34 | asts.append(parser()) 35 | break 36 | except BadStatementException: 37 | self._pos = saved_pos 38 | else: 39 | raise BadStatementException(f'failed to parse tokens started from {self._pos}') 40 | return ListAST(asts) 41 | 42 | def _root_parse_var_def(self) -> AST: 43 | self._expect(TokenKind.U8) 44 | var_ident = self._expect(TokenKind.IDENT) 45 | self._expect(TokenKind.ASSIGN) 46 | val = self._root_parse_expr() 47 | self._expect(TokenKind.SEMICOLON) 48 | return VarDefAST(var_ident.content, val) 49 | 50 | def _root_parse_print(self) -> AST: 51 | self._expect(TokenKind.PRINT) 52 | expr = self._root_parse_expr() 53 | self._expect(TokenKind.SEMICOLON) 54 | return PrintAST(expr) 55 | 56 | def _root_parse_u8_set(self) -> U8SetAST: 57 | list_expr, subscript_expr = self._parse_u8_common_parts() 58 | self._expect(TokenKind.RS) 59 | self._expect(TokenKind.ASSIGN) 60 | value_expr = self._root_parse_expr() 61 | self._expect(TokenKind.SEMICOLON) 62 | return U8SetAST(list_expr, subscript_expr, value_expr) 63 | 64 | def _root_parse_expr(self, skip_u8=False) -> AST: 65 | expr_parsers = [self._parse_empty_u8_expr, self._parse_or_u8_expr, self._parse_u8_get, self._parse_var_expr] 66 | for parser in expr_parsers: 67 | if skip_u8 and parser == self._parse_u8_get: 68 | continue 69 | saved_pos = self._pos 70 | try: 71 | return parser() 72 | except BadStatementException: 73 | self._pos = saved_pos 74 | raise BadStatementException('cannot parse expressions') 75 | 76 | def _parse_empty_u8_expr(self) -> AST: 77 | self._expect(TokenKind.LS) 78 | length = self._expect(TokenKind.NUMBER) 79 | self._expect(TokenKind.RS) 80 | return EmptyU8InitAST(int(length.content)) 81 | 82 | def _parse_or_u8_expr(self) -> OrU8InitAST: 83 | first = self._expect(TokenKind.NUMBER) 84 | 85 | try: 86 | self._expect(TokenKind.OR) 87 | except BadStatementException: 88 | return OrU8InitAST(int(first.content)) 89 | 90 | return OrU8InitAST(int(first.content), self._parse_or_u8_expr()) 91 | 92 | def _parse_var_expr(self) -> VarExprAST: 93 | ident = self._expect(TokenKind.IDENT) 94 | return VarExprAST(ident.content) 95 | 96 | def _parse_u8_get(self) -> U8GetAST: 97 | list_expr, subscript_expr = self._parse_u8_common_parts() 98 | self._expect(TokenKind.RS) 99 | return U8GetAST(list_expr, subscript_expr) 100 | 101 | def _parse_u8_common_parts(self) -> Tuple[AST, AST]: 102 | list_expr = self._root_parse_expr(skip_u8=True) 103 | self._expect(TokenKind.LS) 104 | subscript_expr = self._root_parse_expr() 105 | return list_expr, subscript_expr 106 | -------------------------------------------------------------------------------- /helang/tokens.py: -------------------------------------------------------------------------------- 1 | import enum 2 | 3 | 4 | class TokenKind(enum.Enum): 5 | # Numbers like 123, 276, etc. 6 | NUMBER = 1 7 | # | 8 | OR = 2 9 | # Identifiers 10 | IDENT = 3 11 | # ( 12 | LP = 4 13 | # ) 14 | RP = 5 15 | # { 16 | LC = 6 17 | # } 18 | RC = 7 19 | # [ 20 | LS = 8 21 | # ] 22 | RS = 9 23 | # , 24 | COMMA = 10 25 | # ; 26 | SEMICOLON = 11 27 | # - 28 | MINUS = 12 29 | # ++ 30 | INCREMENT = 13 31 | # = 32 | ASSIGN = 14 33 | # Less than, < 34 | LT = 15 35 | # Keywords 36 | KEYWORD = 16 37 | # Saint He's U8 38 | U8 = 17 39 | # Print statement, supporting for single expression 40 | PRINT = 18 41 | 42 | 43 | SINGLE_CHAR_TOKEN_KINDS = { 44 | '|': TokenKind.OR, 45 | '(': TokenKind.LP, 46 | ')': TokenKind.RP, 47 | '{': TokenKind.LC, 48 | '}': TokenKind.RC, 49 | '[': TokenKind.LS, 50 | ']': TokenKind.RS, 51 | ',': TokenKind.COMMA, 52 | ';': TokenKind.SEMICOLON, 53 | '=': TokenKind.ASSIGN, 54 | '<': TokenKind.LT, 55 | '-': TokenKind.MINUS, 56 | } 57 | 58 | 59 | class Token: 60 | def __init__(self, content: str, kind: TokenKind): 61 | self.content = content 62 | self.kind = kind 63 | 64 | def __eq__(self, other): 65 | return self.content == other.content and self.kind == other.kind -------------------------------------------------------------------------------- /helang/u8.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | 3 | 4 | class U8: 5 | """ 6 | The Saint He's specific type. 7 | """ 8 | def __init__(self, value: Optional[List[int]] = None): 9 | self.value = value 10 | 11 | def __str__(self) -> str: 12 | if self.value is None: 13 | return '' 14 | return ' | '.join(str(element) for element in self.value) 15 | -------------------------------------------------------------------------------- /tests/test_ast.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from helang.he_ast import * 4 | 5 | 6 | class TestAST(unittest.TestCase): 7 | def setUp(self) -> None: 8 | self.env = {'a': U8([1, 2, 3, 4]), 'b': U8([1, 3]), 'c': U8([12])} 9 | self.a = VarExprAST('a') 10 | self.b = VarExprAST('b') 11 | self.c = VarExprAST('c') 12 | 13 | def test_list_get(self): 14 | result = U8GetAST(self.a, self.b).evaluate(self.env) 15 | self.assertEqual(result.value, [1, 3]) 16 | 17 | def test_list_set(self): 18 | U8SetAST(self.a, self.b, self.c).evaluate(self.env) 19 | self.assertEqual(self.env['a'].value, [12, 2, 12, 4]) 20 | -------------------------------------------------------------------------------- /tests/test_lexer.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from helang.lexer import Lexer 4 | from helang.tokens import Token, TokenKind 5 | 6 | 7 | class LexerTester(unittest.TestCase): 8 | def setUp(self) -> None: 9 | self.code = """ 10 | u8 a = 1 | 2 11 | // Comment for single line. 12 | """ 13 | 14 | def test_lex(self): 15 | lexer = Lexer(self.code) 16 | tokens = lexer.lex() 17 | 18 | expected = [ 19 | Token('u8', TokenKind.U8), 20 | Token('a', TokenKind.IDENT), 21 | Token('=', TokenKind.ASSIGN), 22 | Token('1', TokenKind.NUMBER), 23 | Token('|', TokenKind.OR), 24 | Token('2', TokenKind.NUMBER) 25 | ] 26 | 27 | for i in range(len(expected)): 28 | self.assertEqual(tokens[i], expected[i]) 29 | -------------------------------------------------------------------------------- /tests/test_parser.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from helang.parser import Parser 4 | from helang.lexer import Lexer 5 | from helang.u8 import U8 6 | 7 | 8 | class ParserTest(unittest.TestCase): 9 | def setUp(self) -> None: 10 | self.def_code = """ 11 | u8 list1 = 1 | 2 | 3; 12 | u8 list2 = [3]; 13 | """ 14 | 15 | self.u8_set_code = """ 16 | u8 a = 1 | 2 | 3; 17 | a[1 | 3] = 12; 18 | """ 19 | 20 | # You need to provide variable a. 21 | self.u8_get_code = """ 22 | u8 b = a[1 | 3]; 23 | """ 24 | 25 | # You need to provide variable a. 26 | self.print_code = """ 27 | print a[1 | 2]; 28 | """ 29 | 30 | def test_parse_def(self): 31 | lexer = Lexer(self.def_code) 32 | env = dict() 33 | Parser(lexer.lex()).parse().evaluate(env) 34 | self.assertEqual(env['list1'].value, [1, 2, 3]) 35 | self.assertEqual(env['list2'].value, [0, 0, 0]) 36 | 37 | def test_parse_u8_set(self): 38 | env = dict() 39 | Parser(Lexer(self.u8_set_code).lex()).parse().evaluate(env) 40 | self.assertEqual(env['a'].value, [12, 2, 12]) 41 | 42 | def test_parse_u8_get(self): 43 | env = {'a': U8([2, 3, 4])} 44 | Parser(Lexer(self.u8_get_code).lex()).parse().evaluate(env) 45 | self.assertEqual(env['b'].value, [2, 4]) 46 | 47 | def test_parse_print(self): 48 | env = {'a': U8([2, 3, 4])} 49 | printed_content = Parser(Lexer(self.print_code).lex()).parse().evaluate(env) 50 | self.assertEqual(printed_content.value, [2, 3]) 51 | --------------------------------------------------------------------------------