rpython,rust,swift4,ts: fix empty list handling.
authorJoel Martin <github@martintribe.org>
Wed, 8 May 2019 04:38:07 +0000 (23:38 -0500)
committerJoel Martin <github@martintribe.org>
Tue, 7 May 2019 21:43:12 +0000 (16:43 -0500)
In these implementations there is no empty list check before
macroexpansion and so empty lists from step8 onwards produce a crash
or other misbehavior.

Also, add a test to step8 to test empty list again (first time it's
tested is in step2).

17 files changed:
rpython/step8_macros.py
rpython/step9_try.py
rpython/stepA_mal.py
rust/step8_macros.rs
rust/step9_try.rs
rust/stepA_mal.rs
swift4/Sources/step4_if_fn_do/main.swift
swift4/Sources/step5_tco/main.swift
swift4/Sources/step6_file/main.swift
swift4/Sources/step7_quote/main.swift
swift4/Sources/step8_macros/main.swift
swift4/Sources/step9_try/main.swift
swift4/Sources/stepA_mal/main.swift
tests/step8_macros.mal
ts/step8_macros.ts
ts/step9_try.ts
ts/stepA_mal.ts

index 52a47c4..c231b10 100644 (file)
@@ -77,6 +77,7 @@ def EVAL(ast, env):
         #print("EVAL %s" % printer._pr_str(ast))
         if not types._list_Q(ast):
             return eval_ast(ast, env)
+        if len(ast) == 0: return ast
 
         # apply list
         ast = macroexpand(ast, env)
index 6d2d8db..16a4062 100644 (file)
@@ -77,6 +77,7 @@ def EVAL(ast, env):
         #print("EVAL %s" % printer._pr_str(ast))
         if not types._list_Q(ast):
             return eval_ast(ast, env)
+        if len(ast) == 0: return ast
 
         # apply list
         ast = macroexpand(ast, env)
index 0e3d54e..8b1a7f9 100644 (file)
@@ -86,6 +86,7 @@ def EVAL(ast, env):
         #print("EVAL %s" % printer._pr_str(ast))
         if not types._list_Q(ast):
             return eval_ast(ast, env)
+        if len(ast) == 0: return ast
 
         # apply list
         ast = macroexpand(ast, env)
index 70e03fe..bac4269 100644 (file)
@@ -134,6 +134,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
 
   ret = match ast.clone() {
     List(l,_) => {
+      if l.len() == 0 { return Ok(ast); }
       match macroexpand(ast.clone(), &env) {
         (true, Ok(new_ast)) => {
           ast = new_ast;
index 5e36214..557db74 100644 (file)
@@ -135,6 +135,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
 
   ret = match ast.clone() {
     List(l,_) => {
+      if l.len() == 0 { return Ok(ast); }
       match macroexpand(ast.clone(), &env) {
         (true, Ok(new_ast)) => {
           ast = new_ast;
index 89e9135..a870a4b 100644 (file)
@@ -137,6 +137,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
 
   ret = match ast.clone() {
     List(l,_) => {
+      if l.len() == 0 { return Ok(ast); }
       match macroexpand(ast.clone(), &env) {
         (true, Ok(new_ast)) => {
           ast = new_ast;
index e0a2b26..6b8ac01 100644 (file)
@@ -67,7 +67,7 @@ func PRINT(_ input: MalData) -> String {
 }
 
 @discardableResult func rep(_ input: String, env: Env) throws -> String {
-    
+
     return try PRINT(EVAL(READ(input), env: env))
 }
 
index 710e2e1..248d025 100644 (file)
@@ -45,9 +45,9 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData {
                     let fn = {(params: [MalData]) -> MalData in
                         let newEnv = Env(binds: (list[1].listForm as! [Symbol]), exprs: params, outer: env)
                         return try EVAL(list[2], env: newEnv)
-                    } 
+                    }
                     return Function(ast: list[2], params: (list[1].listForm as! [Symbol]), env:env , fn: fn)
-                    
+
                 default:
                     break
                 }
@@ -90,14 +90,13 @@ fn 的 TCO 实现。
         }
     }
 }
-    
+
 
 func PRINT(_ input: MalData) -> String {
     return pr_str(input, print_readably: true)
 }
 
 @discardableResult func rep(_ input: String, env: Env) throws -> String {
-    
     return try PRINT(EVAL(READ(input), env: env))
 }
 
index 8ac611b..d67fa88 100644 (file)
@@ -45,9 +45,9 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData {
                     let fn = {(params: [MalData]) -> MalData in
                         let newEnv = Env(binds: (list[1].listForm as! [Symbol]), exprs: params, outer: env)
                         return try EVAL(list[2], env: newEnv)
-                    } 
+                    }
                     return Function(ast: list[2], params: (list[1].listForm as! [Symbol]), env:env , fn: fn)
-                
+
                 default:
                     break
                 }
index ee8ad12..dc29d6f 100644 (file)
@@ -59,11 +59,11 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData {
                         ast = list[2]
                     }
                     continue
-                case "fn*": 
+                case "fn*":
                     let fn = {(params: [MalData]) -> MalData in
                         let newEnv = Env(binds: (list[1].listForm as! [Symbol]), exprs: params, outer: env)
                         return try EVAL(list[2], env: newEnv)
-                    } 
+                    }
                     return Function(ast: list[2], params: (list[1].listForm as! [Symbol]), env:env , fn: fn)
                 case "quote":
                     return list[1]
index 2886483..7f116be 100644 (file)
@@ -48,6 +48,7 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData {
     while true {
         switch ast.dataType {
         case .List:
+            if (ast as! [MalData]).isEmpty { return ast }
             ast = try macroexpand(ast, env: env)
             guard let list = ast as? [MalData] else { return try eval_ast(ast, env: env) }
             guard !list.isEmpty else { return list }
@@ -85,7 +86,7 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData {
                         ast = list[2]
                     }
                     continue
-                case "fn*": 
+                case "fn*":
                     let fn = {(params: [MalData]) -> MalData in
                         let newEnv = Env(binds: (list[1].listForm as! [Symbol]), exprs: params, outer: env)
                         return try EVAL(list[2], env: newEnv)
index 963a8f4..6e1610d 100644 (file)
@@ -48,6 +48,7 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData {
     while true {
         switch ast.dataType {
         case .List:
+            if (ast as! [MalData]).isEmpty { return ast }
             ast = try macroexpand(ast, env: env)
             guard let list = ast as? [MalData] else { return try eval_ast(ast, env: env) }
             guard !list.isEmpty else { return list }
@@ -85,7 +86,7 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData {
                         ast = list[2]
                     }
                     continue
-                case "fn*": 
+                case "fn*":
                     let fn = {(params: [MalData]) -> MalData in
                         let newEnv = Env(binds: (list[1].listForm as! [Symbol]), exprs: params, outer: env)
                         return try EVAL(list[2], env: newEnv)
@@ -98,7 +99,6 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData {
                     continue
                 case "macroexpand":
                     return try macroexpand(list[1], env: env)
-//                     (try* A (catch* B C))
                 case "try*":
                     do {
                         return try EVAL(list[1], env: env)
index 29cd2b3..9b9e61f 100644 (file)
@@ -48,6 +48,7 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData {
     while true {
         switch ast.dataType {
         case .List:
+            if (ast as! [MalData]).isEmpty { return ast }
             ast = try macroexpand(ast, env: env)
             guard let list = ast as? [MalData] else { return try eval_ast(ast, env: env) }
             guard !list.isEmpty else { return list }
index 8d0ac4b..36e0158 100644 (file)
 (let* (a 123) (identity a))
 ;=>123
 
+;; Test that macros do not break empty list
+()
+;=>()
+
 
 ;>>> deferrable=True
 ;;
index 5de9415..0c91566 100644 (file)
@@ -121,6 +121,9 @@ function evalMal(ast: MalType, env: Env): MalType {
         if (ast.type !== Node.List) {
             return evalAST(ast, env);
         }
+        if (ast.list.length === 0) {
+            return ast;
+        }
 
         ast = macroexpand(ast, env);
         if (!isSeq(ast)) {
index d949938..eb22b39 100644 (file)
@@ -121,6 +121,9 @@ function evalMal(ast: MalType, env: Env): MalType {
         if (ast.type !== Node.List) {
             return evalAST(ast, env);
         }
+        if (ast.list.length === 0) {
+            return ast;
+        }
 
         ast = macroexpand(ast, env);
         if (!isSeq(ast)) {
index 9546cbd..d53e12c 100644 (file)
@@ -121,6 +121,9 @@ function evalMal(ast: MalType, env: Env): MalType {
         if (ast.type !== Node.List) {
             return evalAST(ast, env);
         }
+        if (ast.list.length === 0) {
+            return ast;
+        }
 
         ast = macroexpand(ast, env);
         if (!isSeq(ast)) {