def test_ast_opts(self): a = AST() t = Tokenizer() opts = {} opts['get-me'] = 'I am superman' a.parse(t.parse('{{ opts.get("get-me") }}')) c = a.traverse(opts=opts) self.assertEqual(c.buffer, 'I am superman') a.parse(t.parse('{@ if opts.get("get-me"): @}I am superman{@ end @}')) c = a.traverse(opts=opts) self.assertEqual(c.buffer, 'I am superman')
def test_ast_basic(self): t = Tokenizer() a = AST() a.parse(t.parse('')) self.assertEqual(a.root, None) a.parse(t.parse('abc')) c = a.traverse() self.assertEqual(a.root.text_block.text, 'abc') a.parse(t.parse('{@')) a.parse(t.parse('{@ v = "v"')) with self.assertRaises(AST.SyntaxError): a.parse(t.parse('{@ 1: @}'))
def main(): sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8') sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') try: opts = create_opts() src = sys.stdin.read() tokenizer = Tokenizer() tokens = tokenizer.parse(src) ast = AST() ast.parse(tokens) context = ast.traverse(opts=opts) print(context.buffer) except Tokenizer.ParseError as e: print(e) sys.exit(1) except AST.SyntaxError as e: print(e) sys.exit(2) sys.exit(0)
def test_ast_if(self): t = Tokenizer() a = AST() a.parse(t.parse('{@ if 1: @}abc{@ end @}')) c = a.traverse() self.assertEqual(c.buffer, 'abc') with self.assertRaises(AST.SyntaxError): a.parse(t.parse('{@ if 1 @}{@ end @}')) with self.assertRaises(AST.SyntaxError): a.parse(t.parse('{@ if @}{@ end @}')) with self.assertRaises(AST.SyntaxError): a.parse(t.parse('{@ if 1: @}{@ @}')) a.parse(t.parse('{@ if 1: v = "v" end @}')) c = a.traverse() self.assertEqual(c.syms['v'], 'v') a.parse(t.parse('{@ if 0: v = "v" else: v = "v2" end @}')) c = a.traverse() self.assertEqual(c.syms['v'], 'v2') a.parse(t.parse('{@ if 0: v = "v" elif 1: v = "v2" end @}')) c = a.traverse() self.assertEqual(c.syms['v'], 'v2') a.parse(t.parse('{@ if 0: v = "v" elif 0: v = "v2" else: v = "v3" end @}')) c = a.traverse() self.assertEqual(c.syms['v'], 'v3') a.parse(t.parse('''{@ if 1: v = "s" end @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 's') a.parse(t.parse('''{@ if 1: v = "a" elif 2: v = "b" else: v = "c" end @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse('''{@ if 1: if 2: v = "a" end end @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse('''{@ if 0: else: if 2: v = "abc" end end @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'abc') a.parse(t.parse('''{@ if 1: @}{@ end @}''')) c = a.traverse() a.parse(t.parse('''{@ if 0: @}{@ elif 1: @}{@ v = "a" @}{@ end @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse('''{@ if 0: @}{@ elif 0: @}{@ else: @}{@ v = "a" @}{@ end @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse('''{@ v = "a" @}{@ if 1: @}{@ if 2: @}{{ v }}{@ end @}{@ end @}bbb''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') self.assertEqual(c.buffer, "abbb") a.parse(t.parse('''{@ v = "a" @}{@ if 1: @}{{ v }}{{ v }}{@ end @}''')) a.parse(t.parse('''{@ v = "cat" if 1: @}{{ v }}{@ end if 1: end @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'cat') self.assertEqual(c.buffer, 'cat') a.parse(t.parse('''{@ v = "a" @} {@ if 1: @} {{ v }} {@ end @} bbb''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') self.assertEqual(c.buffer, "a\nbbb") a.parse(t.parse('''{@ v = "a" if 1: v = "b" @}{{ v }}{@ end @} c''')) c = a.traverse() self.assertEqual(c.syms['v'], 'b') self.assertEqual(c.buffer, 'bc') a.parse(t.parse('''{@ if 0: @}{@ else: @}{@ v = "a" @}{@ end @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse('''{@ if 1: @}abc{@ end @}''')) c = a.traverse() a.parse(t.parse('''{@ v = "a" @}{@ if 1: @}{{ v }}{@ end @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') self.assertEqual(c.buffer, 'a') a.parse(t.parse('''{@ v = "a" @}{@ if 0: @}{@ else: @}{{ v }}{@ end @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') self.assertEqual(c.buffer, 'a') a.parse(t.parse(''' {@ if 0: @} {@ else: @} {@ v = "a" @} {@ end @} ''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse(''' {@ if 0: @} {@ elif 1: @} {@ v = "a" @} {@ end @} ''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse('''{@ if 1: @}{@ if 2: @}{@ v = "a" @}{@ end @}{@ end @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse(''' {@ if 1: @} {@ if 2: @} {@ v = "a" @} {@ end @} {@ end @} ''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse(''' {@ if 1: @} {@ if 0: @} {@ elif 1: @} {@ v = "a" @} {@ end @} {@ end @} ''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse(''' {@ if 1: @} {@ if 0: @} {@ elif 0: @} {@ else: @} {@ v = "a" @} {@ end @} {@ end @} ''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse(''' {@ if 1: @} {@ if 0: @} {@ elif 1: @} {@ v = "a" @} {@ end @} {@ end @} ''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse('''{@ if 1: if 2: v = "a" end end @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse('''{@ if 1: if 2: v1 = "a" end else: if 0: elif 4: v2 = "b" end end @}''')) c = a.traverse() self.assertEqual(c.syms['v1'], 'a') a.parse(t.parse(''' {@ if 1: @}{@ if 2: @}{@ v = "a" @}{@ end @}{@ end @} ''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse('''{@ if 1: if 2: @}{@ v = "a" @}{@ end end @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse('''{@ if 1: @}aaa{@ if 2: @}bbb{@ v = "ccc" @}{{ v }}{@ end @}ddd{@ end @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'ccc') self.assertEqual(c.buffer, 'aaabbbcccddd') a.parse(t.parse('''aaa{@ if 1: @}bbb{@ if 2: @}ccc{@ v = "ddd" @}{{ v }}{@ end @}eee{@ end @}fff''')) c = a.traverse() self.assertEqual(c.syms['v'], 'ddd') self.assertEqual(c.buffer, 'aaabbbcccdddeeefff') c = a.traverse() a.parse(t.parse('''{@ if 1: v = "a" elif 0: v = "b" else: v = "c" end @}{{ a }}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'a') a.parse(t.parse('''{@ if 0: v = "a" elif 1: v = "b" else: v = "c" end @}{{ a }}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'b') a.parse(t.parse('''{@ if 0: v = "a" elif 0: v = "b" else: v = "c" end @}{{ a }}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'c') a.parse(t.parse('''{@ if 0: v1 = "v1" elif 1: v2 = "v2" if 0: v3 = "v3" else: v4 = "v4" end end @}{{ a }}''')) c = a.traverse() self.assertEqual('v1' not in c.syms.keys(), True) self.assertEqual(c.syms['v2'], 'v2') self.assertEqual('v3' not in c.syms.keys(), True) self.assertEqual(c.syms['v4'], 'v4') a.parse(t.parse('''{@ if 1: if 2: if 3: v = "v" end end end @}{{ a }}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'v') a.parse(t.parse('''{@ if 1: if 2: if 3: v = "v" end v = "v2" end end @}{{ a }}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'v2') a.parse(t.parse('''{@ if 1: if 2: if 3: v = "v" end end v = "v2" end @}{{ a }}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'v2') a.parse(t.parse('''{@ if 1: v = "v" if 2: if 3: v = "v2" end end end @}{{ a }}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'v2') a.parse(t.parse('''{@ if 1: v = "v" if 2: v = "v2" if 3: end end end @}{{ a }}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'v2')
def test_ast_comparison(self): t = Tokenizer() a = AST() a.parse(t.parse('{@ 0 == 0 @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 1) a.parse(t.parse('{@ 0 != 0 @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 0) a.parse(t.parse('{@ 1 > 0 @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 1) a.parse(t.parse('{@ 1 < 0 @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 0) a.parse(t.parse('{@ 1 >= 0 @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 1) a.parse(t.parse('{@ 1 <= 0 @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 0) a.parse(t.parse('''{@ v = 0 v == 0 @}''')) c = a.traverse() self.assertEqual(c.last_expr_val, 1) a.parse(t.parse('''{@ lhs = 0 rhs = 0 lhs == rhs @}''')) c = a.traverse() self.assertEqual(c.last_expr_val, 1) a.parse(t.parse('''{@ lhs = "a" rhs = 0 lhs == rhs @}''')) c = a.traverse() self.assertEqual(c.last_expr_val, 0) a.parse(t.parse('''{@ lhs = 0 rhs = "a" lhs == rhs @}''')) c = a.traverse() self.assertEqual(c.last_expr_val, 0) a.parse(t.parse('{@ "a" == "b" @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 0) a.parse(t.parse('{@ "a" != "b" @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 1) a.parse(t.parse('{@ "a" < "b" @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 1) a.parse(t.parse('{@ "a" > "b" @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 0) a.parse(t.parse('{@ "a" <= "b" @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 1) a.parse(t.parse('{@ "a" >= "b" @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 0) """ この式はPythonではTrueになる CではFalseだ PHP,Rubyではパースエラーになる == 演算子の結果が bool(または int)であることを考えればこの式の結果は False になるべきだという印象を受ける しかし、ぱっと見た感じでは True が正しいようにも見える Cap ではこれは実装上の簡易さから False として扱う """ a.parse(t.parse('{@ "a" == "a" == "a" @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 0)
def test_ast_assign(self): t = Tokenizer() a = AST() a.parse(t.parse('''{@ a = "s" @}''')) c = a.traverse() self.assertEqual(c.syms['a'], 's') a.parse(t.parse('''{@ a = "s" @}{{ a }}''')) c = a.traverse() self.assertEqual(c.syms['a'], 's') a.parse(t.parse('''{@ v = "v" v = "" @}''')) c = a.traverse() self.assertEqual(c.syms['v'], '') a.parse(t.parse('''{@ v = "v" v = "v2" @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'v2') a.parse(t.parse('''{@ v = "v" v = "" v = "v2" @}''')) c = a.traverse() self.assertEqual(c.syms['v'], 'v2') a.parse(t.parse('''{@ v = "v" @} {@ v = "" @} ''')) c = a.traverse() self.assertEqual(c.syms['v'], '') a.parse(t.parse('''{@ v = "v" @} {@ v = "" @} {@ v = "v2" @} ''')) c = a.traverse() self.assertEqual(c.syms['v'], 'v2') a.parse(t.parse('''{@ v = "" @} {@ v = "v" @} ''')) c = a.traverse() self.assertEqual(c.syms['v'], 'v') a.parse(t.parse('{@ v = 1 + 2 @}')) c = a.traverse() self.assertEqual(c.syms['v'], 3) a.parse(t.parse('{@ v = v = 1 @}')) c = a.traverse() self.assertEqual(c.syms['v'], 1) a.parse(t.parse('{@ v = 1 + 2 * 3 @}')) c = a.traverse() self.assertEqual(c.syms['v'], 7) a.parse(t.parse('{@ v = (1 + 2) * 3 @}')) c = a.traverse() self.assertEqual(c.syms['v'], 9) a.parse(t.parse('{@ v = opts.get("a") @}')) c = a.traverse(opts={ 'a': 'b' }) self.assertEqual(c.syms['v'], "b")
def test_ast_expr(self): t = Tokenizer() a = AST() a.parse(t.parse('{@ 1 + 2 @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 3) a.parse(t.parse('{@ 2 - 1 @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 1) a.parse(t.parse('{@ 2 * 3 @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 6) a.parse(t.parse('{@ 4 / 2 @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 2) a.parse(t.parse('{@ 1 + 2 * 3 @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 7) a.parse(t.parse('{@ 1 + 2 * 3 / 2 @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 4) a.parse(t.parse('{@ (1 + 2) * 3 @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 9) with self.assertRaises(AST.SyntaxError): a.parse(t.parse('{@ (1 + 2 @}')) a.parse(t.parse('{@ v = 1 + 2 @}')) c = a.traverse() self.assertEqual(c.last_expr_val, 3) self.assertEqual(c.syms['v'], 3) a.parse(t.parse('''{@ a = 1 + 2 v = a + 3 @}''')) c = a.traverse() self.assertEqual(c.last_expr_val, 6) self.assertEqual(c.syms['v'], 6)
def test_ast_import(self): t = Tokenizer() a = AST() with self.assertRaises(AST.SyntaxError): a.parse(t.parse('{@ import @}')) a.parse(t.parse('{@ import alias')) c = a.traverse() self.assertEqual(c.imported_alias, True) a.parse(t.parse('{@ import alias @}')) c = a.traverse() self.assertEqual(c.imported_alias, True) a.parse(t.parse('aaa{@ import alias @}bbb{@ import config @}ccc')) c = a.traverse() self.assertEqual(c.imported_alias, True) self.assertEqual(c.imported_config, True) a.parse(t.parse('{@ import alias @}{@ import config @}')) c = a.traverse() self.assertEqual(c.imported_alias, True) self.assertEqual(c.imported_config, True) a.parse(t.parse('''{@ import alias alias.set("dtl", "run bin/date-line/date-line.py") @}''')) c = a.traverse() self.assertEqual(c.alias_map['dtl'], 'run bin/date-line/date-line.py') a.parse(t.parse('''{@ import config config.set("editor", "subl") @}''')) c = a.traverse() self.assertEqual(c.config_map['editor'], 'subl')