[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[原创] 由纯 VBScript 编写的 Lisp 语言解释器 - MAL.VBS

本帖最后由 老刘1号 于 2024-7-2 10:09 编辑

项目描述
  • 一个学习、练习编写解释器,加深对语言特性理解的开源学习项目。
  • 目标是让每一个学习者从头编写一个支持函数作为一等公民、闭包、尾递归优化、垃圾收集、宏、错误处理、元数据的类 Clojure 的 Lisp 方言解释器。
  • 解释器需要内置整数、列表、向量、哈希表、字符串、可变原⼦、符号、函数等数据类型。


项目职责
  • 完成了首个使用 VBScript 语言的解释器实现。
  • VBScript 实现中已 Self-Hosting、且通过全部测试,手写代码约五千行。
  • 正在尝试实现首个使用批处理语言的实现。


遇到的实际问题及解决思路
问题1:解释器要求实现闭包、但 VBScript 语言本身不支持闭包。
  • 整体思路:使用 VBScript 已有的类模拟闭包。
  • 数据结构:使用一个类似并查集的孩子指向父亲结点的多叉树来表示语言中的环境帧。
  • 算法思路:查找变量绑定时首先在当前帧中查找,若无法找到则继续向父级帧中递归查找。

问题2:需要实现尾递归优化。
  • 需求来源:MAL 语言中使用递归实现迭代(无传统语言中的循环结构),不进行优化就会造成空间浪费甚至栈溢出。
  • 尾递归:对函数自身的调用是函数执行的最后一步,之后会返回到上一层栈帧。
  • 优化目标:确保尾递归场景出现时调用栈不累加。
  • 优化思路:使用惰性求值方式,切换函数调用和返回结果的顺序,先移除当前栈帧再进行下次迭代。

问题3:在封装 MAL 的各种数据类型中需要对统一接口做出抽象。
  • 需求来源:封装接口就可以用一套逻辑进行统一处理,不必为每个数据类型编写独立的、单独的逻辑。增强了代码的健壮性。
  • 遇到障碍:VBScript 语言对面向对象的支持非常有限,没有接口、继承、多态特性。
  • 解决思路:VBScript 是动态类型语言,只要在各种数据类型的类中定义相同的属性和方法,就可以模拟接口、继承和多态。

问题4:批处理对字符串封装不足、处理困难。
  • 需求来源:批处理只支持单行千字以内的字符串,处理特殊字符困难。
  • 解决思路(特殊字符):定义一套符号替换逻辑,预先将符号替换为其它字符串,执行完成后再替换回符号本身。
  • 解决思路(单行限制):通过抽象一套字符串数组实现模拟多行字符串支持,数组的每一个元素代表实际的一行字符。
  • 一些思考:替换操作导致了额外的性能开销,是否有更好的方式?

问题5:批处理难以对复杂逻辑进行抽象。
  • 需求来源:批处理中没有函数概念,只有标号、跳转和简单的过程调用。
  • 解决思路:构造一个全局栈,模拟函数栈帧。使用全局栈完成参数传递、备份、返回值传递的需求。
  • 一些思考:是否可以不借助函数这层抽象就完成项目实现?


印象深刻的 BUGs
  • 由于 VBScript 默认为按地址传递参数,导致修改函数实参时影响到调用者传入变量的值。
  • 在异常捕获语句块中再次抛出异常,逻辑上处理有误导致项目奔溃。


一些开放性问题
  • 代码简洁和运行效率之间如何取舍?
  • 引入函数作为一等公民、闭包对语言复杂性、性能有何影响?
  • 舍弃循环,统一使用递归实现迭代,真的合理吗?
  • 在有复杂逻辑的项目中如何进行高效的 Debug?


项目地址
  1. ' mal.vbs
  2. ' A MAL (Lisp) Language Interpreter witten in VBScript
  3. ' Code by OldLiu (632171029@qq.com)
  4. ' https://github.com/kanaka/mal
  5. ' https://github.com/OldLiu001/mal/tree/master/impls/vbs
  6. Option Explicit
  7. CreateObject("System.Collections.ArrayList")
  8. Const strHost = "CSCRIPT.EXE" 'WSCRIPT
  9. If Not UCase(Right(WScript.FullName,11)) = UCase(strHost) Then
  10.         Dim Args,Arg
  11.         For Each Arg in Wscript.Arguments
  12.                 Args=Args&Chr(&H20)&Chr(&H22)&Arg&Chr(&H22)
  13.         Next
  14.         CreateObject("Wscript.Shell").Run _
  15.                 strHost&Chr(&H20)&Chr(&H22)&WScript.ScriptFullName&Chr(&H22)&Args
  16.         WScript.Quit
  17. End If
  18. Dim TYPES
  19. Set TYPES = New MalTypes
  20. Class MalTypes
  21.         Public LIST, VECTOR, HASHMAP, [BOOLEAN], NIL
  22.         Public KEYWORD, [STRING], NUMBER, SYMBOL
  23.         Public PROCEDURE, ATOM
  24.         Public [TypeName]
  25.         Private Sub Class_Initialize
  26.                 [TypeName] = Array( _
  27.                                 "LIST", "VECTOR", "HASHMAP", "BOOLEAN", _
  28.                                 "NIL", "KEYWORD", "STRING", "NUMBER", _
  29.                                 "SYMBOL", "PROCEDURE", "ATOM")
  30.                 Dim i
  31.                 For i = 0 To UBound([TypeName])
  32.                         Execute "[" + [TypeName](i) + "] = " + CStr(i)
  33.                 Next
  34.         End Sub
  35. End Class
  36. Class MalType
  37.         Public [Type]
  38.         Public Value
  39.         Private varMeta
  40.         Public Property Get MetaData()
  41.                 If IsEmpty(varMeta) Then
  42.                         Set MetaData = NewMalNil()
  43.                 Else
  44.                         Set MetaData = varMeta
  45.                 End If
  46.         End Property
  47.         
  48.         Public Property Set MetaData(objMeta)
  49.                 Set varMeta = objMeta
  50.         End Property
  51.         
  52.         Public Function Copy()
  53.                 Set Copy = NewMalType([Type], Value)
  54.         End Function
  55.         Public Function Init(lngType, varValue)
  56.                 [Type] = lngType
  57.                 Value = varValue
  58.         End Function
  59. End Class
  60. Function NewMalType(lngType, varValue)
  61.         Dim varResult
  62.         Set varResult = New MalType
  63.         varResult.Init lngType, varValue
  64.         Set NewMalType = varResult
  65. End Function
  66. Function NewMalBool(varValue)
  67.         Set NewMalBool = NewMalType(TYPES.BOOLEAN, varValue)
  68. End Function
  69. Function NewMalNil()
  70.         Set NewMalNil = NewMalType(TYPES.NIL, Empty)
  71. End Function
  72. Function NewMalKwd(varValue)
  73.         Set NewMalKwd = NewMalType(TYPES.KEYWORD, varValue)
  74. End Function
  75. Function NewMalStr(varValue)
  76.         Set NewMalStr = NewMalType(TYPES.STRING, varValue)
  77. End Function
  78. Function NewMalNum(varValue)
  79.         Set NewMalNum = NewMalType(TYPES.NUMBER, varValue)
  80. End Function
  81. Function NewMalSym(varValue)
  82.         Set NewMalSym = NewMalType(TYPES.SYMBOL, varValue)
  83. End Function
  84. Class MalAtom
  85.         Public [Type]
  86.         Public Value
  87.         
  88.         Private varMeta
  89.         Public Property Get MetaData()
  90.                 If IsEmpty(varMeta) Then
  91.                         Set MetaData = NewMalNil()
  92.                 Else
  93.                         Set MetaData = varMeta
  94.                 End If
  95.         End Property
  96.         
  97.         Public Property Set MetaData(objMeta)
  98.                 Set varMeta = objMeta
  99.         End Property
  100.         Public Function Copy()
  101.                 Set Copy = NewMalAtom(Value)
  102.         End Function
  103.         Public Sub Reset(objMal)
  104.                 Set Value = objMal
  105.         End Sub
  106.         Private Sub Class_Initialize
  107.                 [Type] = TYPES.ATOM
  108.         End Sub
  109. End Class
  110. Function NewMalAtom(varValue)
  111.         Dim varRes
  112.         Set varRes = New MalAtom
  113.         varRes.Reset varValue
  114.         Set NewMalAtom = varRes
  115. End Function
  116. Class MalList ' Extends MalType
  117.         Public [Type]
  118.         Public Value
  119.         
  120.         Private varMeta
  121.         Public Property Get MetaData()
  122.                 If IsEmpty(varMeta) Then
  123.                         Set MetaData = NewMalNil()
  124.                 Else
  125.                         Set MetaData = varMeta
  126.                 End If
  127.         End Property
  128.         
  129.         Public Property Set MetaData(objMeta)
  130.                 Set varMeta = objMeta
  131.         End Property
  132.         Public Function Copy()
  133.                 Set Copy = New MalList
  134.                 Set Copy.Value = Value
  135.         End Function
  136.         Private Sub Class_Initialize
  137.                 [Type] = TYPES.LIST
  138.                 Set Value = CreateObject("System.Collections.ArrayList")
  139.         End Sub
  140.         Public Function Init(arrValues)
  141.                 Dim i
  142.                 For i = 0 To UBound(arrValues)
  143.                         Add arrValues(i)
  144.                 Next
  145.         End Function
  146.         Public Function Add(objMalType)
  147.                 Value.Add objMalType
  148.         End Function
  149.         
  150.         Public Property Get Item(i)
  151.                 Set Item = Value.Item(i)
  152.         End Property
  153.         Public Property Let Item(i, varValue)
  154.                 Value.Item(i) = varValue
  155.         End Property
  156.         Public Property Set Item(i, varValue)
  157.                 Set Value.Item(i) = varValue
  158.         End Property
  159.         Public Function Count()
  160.                 Count = Value.Count
  161.         End Function
  162. End Class
  163. Function NewMalList(arrValues)
  164.         Dim varResult
  165.         Set varResult = New MalList
  166.         varResult.Init arrValues
  167.         Set NewMalList = varResult
  168. End Function
  169. Class MalVector ' Extends MalType
  170.         Public [Type]
  171.         Public Value
  172.         
  173.         Private varMeta
  174.         Public Property Get MetaData()
  175.                 If IsEmpty(varMeta) Then
  176.                         Set MetaData = NewMalNil()
  177.                 Else
  178.                         Set MetaData = varMeta
  179.                 End If
  180.         End Property
  181.         
  182.         Public Property Set MetaData(objMeta)
  183.                 Set varMeta = objMeta
  184.         End Property
  185.         Public Function Copy()
  186.                 Set Copy = New MalVector
  187.                 Set Copy.Value = Value
  188.         End Function
  189.         Private Sub Class_Initialize
  190.                 [Type] = TYPES.VECTOR
  191.                 Set Value = CreateObject("System.Collections.ArrayList")
  192.         End Sub
  193.         Public Function Init(arrValues)
  194.                 Dim i
  195.                 For i = 0 To UBound(arrValues)
  196.                         Add arrValues(i)
  197.                 Next
  198.         End Function
  199.         Public Function Add(objMalType)
  200.                 Value.Add objMalType
  201.         End Function
  202.         
  203.         Public Property Get Item(i)
  204.                 Set Item = Value.Item(i)
  205.         End Property
  206.         Public Property Let Item(i, varValue)
  207.                 Value.Item(i) = varValue
  208.         End Property
  209.         Public Property Set Item(i, varValue)
  210.                 Set Value.Item(i) = varValue
  211.         End Property
  212.         Public Function Count()
  213.                 Count = Value.Count
  214.         End Function
  215. End Class
  216. Function NewMalVec(arrValues)
  217.         Dim varResult
  218.         Set varResult = New MalVector
  219.         varResult.Init arrValues
  220.         Set NewMalVec = varResult
  221. End Function
  222. Class MalHashmap 'Extends MalType
  223.         Public [Type]
  224.         Public Value
  225.         Private varMeta
  226.         Public Property Get MetaData()
  227.                 If IsEmpty(varMeta) Then
  228.                         Set MetaData = NewMalNil()
  229.                 Else
  230.                         Set MetaData = varMeta
  231.                 End If
  232.         End Property
  233.         
  234.         Public Property Set MetaData(objMeta)
  235.                 Set varMeta = objMeta
  236.         End Property
  237.         Public Function Copy()
  238.                 Set Copy = New MalHashmap
  239.                 Set Copy.Value = Value
  240.         End Function
  241.         Private Sub Class_Initialize
  242.                 [Type] = TYPES.HASHMAP
  243.                 Set Value = CreateObject("Scripting.Dictionary")
  244.         End Sub
  245.         Public Function Init(arrKeys, arrValues)
  246.                 Dim i
  247.                 For i = 0 To UBound(arrKeys)
  248.                         Add arrKeys(i), arrValues(i)
  249.                 Next
  250.         End Function
  251.         Private Function M2S(objKey)
  252.                 Dim varRes
  253.                 Select Case objKey.Type
  254.                         Case TYPES.STRING
  255.                                 varRes = "S" + objKey.Value
  256.                         Case TYPES.KEYWORD
  257.                                 varRes = "K" + objKey.Value
  258.                         Case Else
  259.                                 Err.Raise vbObjectError, _
  260.                                         "MalHashmap", "Unexpect key type."
  261.                 End Select
  262.                 M2S = varRes
  263.         End Function
  264.         Private Function S2M(strKey)
  265.                 Dim varRes
  266.                 Select Case Left(strKey, 1)
  267.                         Case "S"
  268.                                 Set varRes = NewMalStr(Right(strKey, Len(strKey) - 1))
  269.                         Case "K"
  270.                                 Set varRes = NewMalKwd(Right(strKey, Len(strKey) - 1))
  271.                         Case Else
  272.                                 Err.Raise vbObjectError, _
  273.                                         "MalHashmap", "Unexpect key type."
  274.                 End Select
  275.                 Set S2M = varRes
  276.         End Function
  277.         Public Function Add(varKey, varValue)
  278.                 If varKey.Type <> TYPES.STRING And _
  279.                         varKey.Type <> TYPES.KEYWORD Then
  280.                         Err.Raise vbObjectError, _
  281.                                 "MalHashmap", "Unexpect key type."
  282.                 End If
  283.                
  284.                 Set Value.Item(M2S(varKey)) = varValue
  285.                 'Value.Add M2S(varKey), varValue
  286.         End Function
  287.         
  288.         Public Property Get Keys()
  289.                 Dim aKeys
  290.                 aKeys = Value.Keys
  291.                 Dim aRes()
  292.                 ReDim aRes(UBound(aKeys))
  293.                 Dim i
  294.                 For i = 0 To UBound(aRes)
  295.                         Set aRes(i) = S2M(aKeys(i))
  296.                 Next
  297.                 Keys = aRes
  298.         End Property
  299.         Public Function Count()
  300.                 Count = Value.Count
  301.         End Function
  302.         Public Property Get Item(i)
  303.                 Set Item = Value.Item(M2S(i))
  304.         End Property
  305.         Public Function Exists(varKey)
  306.                 If varKey.Type <> TYPES.STRING And _
  307.                         varKey.Type <> TYPES.KEYWORD Then
  308.                         Err.Raise vbObjectError, _
  309.                                 "MalHashmap", "Unexpect key type."
  310.                 End If
  311.                 Exists = Value.Exists(M2S(varKey))
  312.         End Function
  313.         Public Property Let Item(i, varValue)
  314.                 Value.Item(M2S(i)) = varValue
  315.         End Property
  316.         Public Property Set Item(i, varValue)
  317.                 Set Value.Item(M2S(i)) = varValue
  318.         End Property
  319. End Class
  320. Function NewMalMap(arrKeys, arrValues)
  321.         Dim varResult
  322.         Set varResult = New MalHashmap
  323.         varResult.Init arrKeys, arrValues
  324.         Set NewMalMap = varResult
  325. End Function
  326. Class VbsProcedure 'Extends MalType
  327.         Public [Type]
  328.         Public Value
  329.         
  330.         Public IsMacro
  331.         Public boolSpec
  332.         Public MetaData
  333.         Private Sub Class_Initialize
  334.                 [Type] = TYPES.PROCEDURE
  335.                 IsMacro = False
  336.                 Set MetaData = NewMalNil()
  337.         End Sub
  338.         Public Property Get IsSpecial()
  339.                 IsSpecial = boolSpec
  340.         End Property
  341.         Public Function Init(objFunction, boolIsSpec)
  342.                 Set Value = objFunction
  343.                 boolSpec = boolIsSpec
  344.         End Function
  345.         Public Function Apply(objArgs, objEnv)
  346.                 Dim varResult
  347.                 If boolSpec Then
  348.                         Set varResult = Value(objArgs, objEnv)
  349.                 Else
  350.                         Set varResult = Value(EvaluateRest(objArgs, objEnv), objEnv)
  351.                 End If
  352.                 Set Apply = varResult
  353.         End Function
  354.         Public Function ApplyWithoutEval(objArgs, objEnv)
  355.                 Dim varResult
  356.                 Set varResult = Value(objArgs, objEnv)
  357.                
  358.                 Set ApplyWithoutEval = varResult
  359.         End Function
  360.         Public Function Copy()
  361.                 Dim varRes
  362.                 Set varRes = New VbsProcedure
  363.                 varRes.Type = [Type]
  364.                 Set varRes.Value = Value
  365.                 varRes.IsMacro = IsMacro
  366.                 varRes.boolSpec = boolSpec
  367.                 Set Copy = varRes
  368.         End Function
  369. End Class
  370. Function NewVbsProc(strFnName, boolSpec)
  371.         Dim varResult
  372.         Set varResult = New VbsProcedure
  373.         varResult.Init GetRef(strFnName), boolSpec
  374.         Set NewVbsProc = varResult
  375. End Function
  376. Class MalProcedure 'Extends MalType
  377.         Public [Type]
  378.         Public Value
  379.         
  380.         Public IsMacro
  381.         Public Property Get IsSpecial()
  382.                 IsSpecial = False
  383.         End Property
  384.         Public MetaData
  385.         Private Sub Class_Initialize
  386.                 [Type] = TYPES.PROCEDURE
  387.                 IsMacro = False
  388.                 Set MetaData = NewMalNil()
  389.         End Sub
  390.         Public objParams, objCode, objSavedEnv
  391.         Public Function Init(objP, objC, objE)
  392.                 Set objParams = objP
  393.                 Set objCode = objC
  394.                 Set objSavedEnv = objE
  395.         End Function
  396.         Public Function Apply(objArgs, objEnv)
  397.                 If IsMacro Then
  398.                         Err.Raise vbObjectError, _
  399.                                 "MalProcedureApply", "Not a procedure."
  400.                 End If
  401.                 Dim varRet
  402.                 Dim objNewEnv
  403.                 Set objNewEnv = NewEnv(objSavedEnv)
  404.                 Dim i
  405.                 i = 0
  406.                 Dim objList
  407.                 While i < objParams.Count
  408.                         If objParams.Item(i).Value = "&" Then
  409.                                 If objParams.Count - 1 = i + 1 Then
  410.                                         Set objList = NewMalList(Array())
  411.                                         objNewEnv.Add objParams.Item(i + 1), objList
  412.                                         While i + 1 < objArgs.Count
  413.                                                 objList.Add Evaluate(objArgs.Item(i + 1), objEnv)
  414.                                                 i = i + 1
  415.                                         Wend
  416.                                         i = objParams.Count ' Break While
  417.                                 Else
  418.                                         Err.Raise vbObjectError, _
  419.                                                 "MalProcedureApply", "Invalid parameter(s)."
  420.                                 End If
  421.                         Else
  422.                                 If i + 1 >= objArgs.Count Then
  423.                                         Err.Raise vbObjectError, _
  424.                                                 "MalProcedureApply", "Need more arguments."
  425.                                 End If
  426.                                 objNewEnv.Add objParams.Item(i), _
  427.                                         Evaluate(objArgs.Item(i + 1), objEnv)
  428.                                 i = i + 1
  429.                         End If
  430.                 Wend
  431.                
  432.                 Set varRet = EvalLater(objCode, objNewEnv)
  433.                 Set Apply = varRet
  434.         End Function
  435.         Public Function MacroApply(objArgs, objEnv)
  436.                 If Not IsMacro Then
  437.                         Err.Raise vbObjectError, _
  438.                                 "MalMacroApply", "Not a macro."
  439.                 End If
  440.                 Dim varRet
  441.                 Dim objNewEnv
  442.                 Set objNewEnv = NewEnv(objSavedEnv)
  443.                 Dim i
  444.                 i = 0
  445.                 Dim objList
  446.                 While i < objParams.Count
  447.                         If objParams.Item(i).Value = "&" Then
  448.                                 If objParams.Count - 1 = i + 1 Then
  449.                                         Set objList = NewMalList(Array())
  450.                                        
  451.                                         ' No evaluation
  452.                                         objNewEnv.Add objParams.Item(i + 1), objList
  453.                                         While i + 1 < objArgs.Count
  454.                                                 objList.Add objArgs.Item(i + 1)
  455.                                                 i = i + 1
  456.                                         Wend
  457.                                         i = objParams.Count ' Break While
  458.                                 Else
  459.                                         Err.Raise vbObjectError, _
  460.                                                 "MalMacroApply", "Invalid parameter(s)."
  461.                                 End If
  462.                         Else
  463.                                 If i + 1 >= objArgs.Count Then
  464.                                         Err.Raise vbObjectError, _
  465.                                                 "MalMacroApply", "Need more arguments."
  466.                                 End If
  467.                                 
  468.                                 ' No evaluation
  469.                                 objNewEnv.Add objParams.Item(i), _
  470.                                         objArgs.Item(i + 1)
  471.                                 i = i + 1
  472.                         End If
  473.                 Wend
  474.                
  475.                 ' EvalLater -> Evaluate
  476.                 Set varRet = Evaluate(objCode, objNewEnv)
  477.                 Set MacroApply = varRet
  478.         End Function
  479.         Public Function ApplyWithoutEval(objArgs, objEnv)
  480.                 Dim varRet
  481.                 Dim objNewEnv
  482.                 Set objNewEnv = NewEnv(objSavedEnv)
  483.                 Dim i
  484.                 i = 0
  485.                 Dim objList
  486.                 While i < objParams.Count
  487.                         If objParams.Item(i).Value = "&" Then
  488.                                 If objParams.Count - 1 = i + 1 Then
  489.                                         Set objList = NewMalList(Array())
  490.                                        
  491.                                         ' No evaluation
  492.                                         objNewEnv.Add objParams.Item(i + 1), objList
  493.                                         While i + 1 < objArgs.Count
  494.                                                 objList.Add objArgs.Item(i + 1)
  495.                                                 i = i + 1
  496.                                         Wend
  497.                                         i = objParams.Count ' Break While
  498.                                 Else
  499.                                         Err.Raise vbObjectError, _
  500.                                                 "MalMacroApply", "Invalid parameter(s)."
  501.                                 End If
  502.                         Else
  503.                                 If i + 1 >= objArgs.Count Then
  504.                                         Err.Raise vbObjectError, _
  505.                                                 "MalMacroApply", "Need more arguments."
  506.                                 End If
  507.                                 
  508.                                 ' No evaluation
  509.                                 objNewEnv.Add objParams.Item(i), _
  510.                                         objArgs.Item(i + 1)
  511.                                 i = i + 1
  512.                         End If
  513.                 Wend
  514.                
  515.                 ' EvalLater -> Evaluate
  516.                 Set varRet = Evaluate(objCode, objNewEnv)
  517.                 Set ApplyWithoutEval = varRet
  518.         End Function
  519.         
  520.         Public Function Copy()
  521.                 Dim varRes
  522.                 Set varRes = New MalProcedure
  523.                 varRes.Type = [Type]
  524.                 varRes.Value = Value
  525.                 varRes.IsMacro = IsMacro
  526.                 Set varRes.objParams = objParams
  527.                 Set varRes.objCode = objCode
  528.                 Set varRes.objSavedEnv = objSavedEnv
  529.                 Set Copy = varRes
  530.         End Function
  531. End Class
  532. Function NewMalProc(objParams, objCode, objEnv)
  533.         Dim varRet
  534.         Set varRet = New MalProcedure
  535.         varRet.Init objParams, objCode, objEnv
  536.         Set NewMalProc = varRet
  537. End Function
  538. Function NewMalMacro(objParams, objCode, objEnv)
  539.         Dim varRet
  540.         Set varRet = New MalProcedure
  541.         varRet.Init objParams, objCode, objEnv
  542.         varRet.IsMacro = True
  543.         Set NewMalProc = varRet
  544. End Function
  545. Function SetMeta(objMal, objMeta)
  546.         Dim varRes
  547.         Set varRes = objMal.Copy
  548.         Set varRes.MetaData = objMeta
  549.         Set SetMeta = varRes
  550. End Function
  551. Function GetMeta(objMal)
  552.         Set GetMeta = objMal.MetaData
  553. End Function
  554. Function ReadString(strCode)
  555.         Dim objTokens
  556.         Set objTokens = Tokenize(strCode)
  557.         Set ReadString = ReadForm(objTokens)
  558.         If Not objTokens.AtEnd() Then
  559.                 Err.Raise vbObjectError, _
  560.                         "ReadForm", "extra token '" + objTokens.Current() + "'."
  561.         End If
  562. End Function
  563. Class Tokens
  564.         Private objQueue
  565.         Private objRE
  566.         Private Sub Class_Initialize
  567.                 Set objRE = New RegExp
  568.                 With objRE
  569.                         .Pattern = "[\s,]*" + _
  570.                                 "(" + _
  571.                                         "~@" + "|" + _
  572.                                         "[\[\]{}()'`~^@]" + "|" + _
  573.                                         """(?:\\.|[^\\""])*""?" + "|" + _
  574.                                         ";.*" + "|" + _
  575.                                         "[^\s\[\]{}('""`,;)]*" + _
  576.                                 ")"
  577.                         .IgnoreCase = True
  578.                         .Global = True
  579.                 End With
  580.                 Set objQueue = CreateObject("System.Collections.Queue")
  581.         End Sub
  582.         Public Function Init(strCode)
  583.                 Dim objMatches, objMatch
  584.                 Set objMatches = objRE.Execute(strCode)
  585.                 Dim strToken
  586.                 For Each objMatch In objMatches
  587.                         strToken = Trim(objMatch.SubMatches(0))
  588.                         If Not (Left(strToken, 1) = ";" Or strToken = "") Then
  589.                                 objQueue.Enqueue strToken
  590.                         End If
  591.                 Next
  592.         End Function
  593.         Public Function Current()
  594.                 Current = objQueue.Peek()
  595.         End Function
  596.         Public Function MoveToNext()
  597.                 MoveToNext = objQueue.Dequeue()
  598.         End Function
  599.         Public Function AtEnd()
  600.                 AtEnd = (objQueue.Count = 0)
  601.         End Function
  602.         Public Function Count()
  603.                 Count = objQueue.Count
  604.         End Function
  605. End Class
  606. Function Tokenize(strCode) ' Return objTokens
  607.         Dim varResult
  608.         Set varResult = New Tokens
  609.         varResult.Init strCode
  610.         Set Tokenize = varResult
  611. End Function
  612. Function ReadForm(objTokens) ' Return Nothing / MalType
  613.         If objTokens.AtEnd() Then
  614.                 Set ReadForm = Nothing
  615.                 Exit Function
  616.         End If
  617.         Dim strToken
  618.         strToken = objTokens.Current()
  619.         Dim varResult
  620.         If InStr("([{", strToken) Then
  621.                 Select Case strToken
  622.                         Case "("
  623.                                 Set varResult = ReadList(objTokens)
  624.                         Case "["
  625.                                 Set varResult = ReadVector(objTokens)
  626.                         Case "{"
  627.                                 Set varResult = ReadHashmap(objTokens)
  628.                 End Select
  629.         ElseIf InStr("'`~@", strToken) Then
  630.                 Set varResult = ReadSpecial(objTokens)
  631.         ElseIf InStr(")]}", strToken) Then
  632.                 Err.Raise vbObjectError, _
  633.                         "ReadForm", "unbalanced parentheses."
  634.         ElseIf strToken = "^" Then
  635.                 Set varResult = ReadMetadata(objTokens)
  636.         Else
  637.                 Set varResult = ReadAtom(objTokens)
  638.         End If
  639.         Set ReadForm = varResult
  640. End Function
  641. Function ReadMetadata(objTokens)
  642.         Dim varResult
  643.         Call objTokens.MoveToNext()
  644.         Dim objTemp
  645.         Set objTemp = ReadForm(objTokens)
  646.         Set varResult = NewMalList(Array( _
  647.                 NewMalSym("with-meta"), _
  648.                 ReadForm(objTokens), objTemp))
  649.         Set ReadMetadata = varResult
  650. End Function
  651. Function ReadSpecial(objTokens)
  652.         Dim varResult
  653.         Dim strToken, strAlias
  654.         strToken = objTokens.Current()
  655.         Select Case strToken
  656.                 Case "'"
  657.                         strAlias = "quote"
  658.                 Case "`"
  659.                         strAlias = "quasiquote"
  660.                 Case "~"
  661.                         strAlias = "unquote"
  662.                 Case "~@"
  663.                         strAlias = "splice-unquote"
  664.                 Case "@"
  665.                         strAlias = "deref"
  666.                 Case Else
  667.                         Err.Raise vbObjectError, _
  668.                                 "ReadSpecial", "unknown token '" & strAlias & "'."
  669.         End Select
  670.         Call objTokens.MoveToNext()
  671.         Set varResult = NewMalList(Array( _
  672.                 NewMalSym(strAlias), _
  673.                 ReadForm(objTokens)))
  674.         Set ReadSpecial = varResult
  675. End Function
  676. Function ReadList(objTokens)
  677.         Dim varResult
  678.         Call objTokens.MoveToNext()
  679.         If objTokens.AtEnd() Then
  680.                 Err.Raise vbObjectError, _
  681.                         "ReadList", "unbalanced parentheses."
  682.         End If
  683.         Set varResult = NewMalList(Array())
  684.         With varResult
  685.                 While objTokens.Count() > 1 And objTokens.Current() <> ")"
  686.                         .Add ReadForm(objTokens)
  687.                 Wend
  688.         End With
  689.         If objTokens.MoveToNext() <> ")" Then
  690.                 Err.Raise vbObjectError, _
  691.                         "ReadList", "unbalanced parentheses."
  692.         End If
  693.         Set ReadList = varResult
  694. End Function
  695. Function ReadVector(objTokens)
  696.         Dim varResult
  697.         Call objTokens.MoveToNext()
  698.         If objTokens.AtEnd() Then
  699.                 Err.Raise vbObjectError, _
  700.                         "ReadVector", "unbalanced parentheses."
  701.         End If
  702.         Set varResult = NewMalVec(Array())
  703.         With varResult
  704.                 While objTokens.Count() > 1 And objTokens.Current() <> "]"
  705.                         .Add ReadForm(objTokens)
  706.                 Wend
  707.         End With
  708.         If objTokens.MoveToNext() <> "]" Then
  709.                 Err.Raise vbObjectError, _
  710.                         "ReadVector", "unbalanced parentheses."
  711.         End If
  712.         Set ReadVector = varResult
  713. End Function
  714. Function ReadHashmap(objTokens)
  715.         Dim varResult
  716.         Call objTokens.MoveToNext()
  717.         If objTokens.Count = 0 Then
  718.                 Err.Raise vbObjectError, _
  719.                         "ReadHashmap", "unbalanced parentheses."
  720.         End If
  721.         
  722.         Set varResult = NewMalMap(Array(), Array())
  723.         Dim objKey, objValue
  724.         With varResult
  725.                 While objTokens.Count > 2 And objTokens.Current() <> "}"
  726.                         Set objKey = ReadForm(objTokens)
  727.                         Set objValue = ReadForm(objTokens)
  728.                         .Add objKey, objValue
  729.                 Wend
  730.         End With
  731.         
  732.         If objTokens.MoveToNext() <> "}" Then
  733.                 Err.Raise vbObjectError, _
  734.                         "ReadHashmap", "unbalanced parentheses."
  735.         End If
  736.         
  737.         Set ReadHashmap = varResult
  738. End Function
  739. Function ReadAtom(objTokens)
  740.         Dim varResult
  741.         Dim strAtom
  742.         strAtom = objTokens.MoveToNext()
  743.         Select Case strAtom
  744.                 Case "true"
  745.                         Set varResult = NewMalBool(True)
  746.                 Case "false"
  747.                         Set varResult = NewMalBool(False)
  748.                 Case "nil"
  749.                         Set varResult = NewMalNil()
  750.                 Case Else
  751.                         Select Case Left(strAtom, 1)
  752.                                 Case ":"
  753.                                         Set varResult = NewMalKwd(strAtom)
  754.                                 Case """"
  755.                                         Set varResult = NewMalStr(ParseString(strAtom))
  756.                                 Case Else
  757.                                         If IsNumeric(strAtom) Then
  758.                                                 Set varResult = NewMalNum(Eval(strAtom))
  759.                                         Else
  760.                                                 Set varResult = NewMalSym(strAtom)
  761.                                         End If
  762.                         End Select
  763.         End Select
  764.         Set ReadAtom = varResult
  765. End Function
  766. Function ParseString(strRaw)
  767.         If Right(strRaw, 1) <> """" Or Len(strRaw) < 2 Then
  768.                 Err.Raise vbObjectError, _
  769.                         "ParseString", "unterminated string, got EOF."
  770.         End If
  771.         Dim strTemp
  772.         strTemp = Mid(strRaw, 2, Len(strRaw) - 2)
  773.         Dim i
  774.         i = 1
  775.         ParseString = ""
  776.         While i <= Len(strTemp) - 1
  777.                 Select Case Mid(strTemp, i, 2)
  778.                         Case "\\"
  779.                                 ParseString = ParseString & "\"
  780.                         Case "\n"
  781.                                 ParseString = ParseString & vbCrLf
  782.                         Case "\"""
  783.                                 ParseString = ParseString & """"
  784.                         Case Else
  785.                                 ParseString = ParseString & Mid(strTemp, i, 1)
  786.                                 i = i - 1
  787.                 End Select
  788.                 i = i + 2
  789.         Wend
  790.         If i <= Len(strTemp) Then
  791.                 ' Last char is not processed.
  792.                 If Right(strTemp, 1) <> "\" Then
  793.                         ParseString = ParseString & Right(strTemp, 1)
  794.                 Else
  795.                         Err.Raise vbObjectError, _
  796.                                 "ParseString", "unterminated string, got EOF."
  797.                 End If
  798.         End If
  799. End Function
  800. Function PrintMalType(objMal, boolReadable)
  801.         Dim varResult
  802.         varResult = ""
  803.         If TypeName(objMal) = "Nothing" Then
  804.                 PrintMalType = ""
  805.                 Exit Function
  806.         End If
  807.         
  808.         Dim i
  809.         Select Case objMal.Type
  810.                 Case TYPES.LIST
  811.                         With objMal
  812.                                 For i = 0 To .Count - 2
  813.                                         varResult = varResult & _
  814.                                                 PrintMalType(.Item(i), boolReadable) & " "
  815.                                 Next
  816.                                 If .Count > 0 Then
  817.                                         varResult = varResult & _
  818.                                                 PrintMalType(.Item(.Count - 1), boolReadable)
  819.                                 End If
  820.                         End With
  821.                         varResult = "(" & varResult & ")"
  822.                 Case TYPES.VECTOR
  823.                         With objMal
  824.                                 For i = 0 To .Count - 2
  825.                                         varResult = varResult & _
  826.                                                 PrintMalType(.Item(i), boolReadable) & " "
  827.                                 Next
  828.                                 If .Count > 0 Then
  829.                                         varResult = varResult & _
  830.                                                 PrintMalType(.Item(.Count - 1), boolReadable)
  831.                                 End If
  832.                         End With
  833.                         varResult = "[" & varResult & "]"
  834.                 Case TYPES.HASHMAP
  835.                         With objMal
  836.                                 Dim arrKeys
  837.                                 arrKeys = .Keys
  838.                                 For i = 0 To .Count - 2
  839.                                         varResult = varResult & _
  840.                                                 PrintMalType(arrKeys(i), boolReadable) & " " & _
  841.                                                 PrintMalType(.Item(arrKeys(i)), boolReadable) & " "
  842.                                 Next
  843.                                 If .Count > 0 Then
  844.                                         varResult = varResult & _
  845.                                                 PrintMalType(arrKeys(.Count - 1), boolReadable) & " " & _
  846.                                                 PrintMalType(.Item(arrKeys(.Count - 1)), boolReadable)
  847.                                 End If
  848.                         End With
  849.                         varResult = "{" & varResult & "}"
  850.                 Case TYPES.STRING
  851.                         If boolReadable Then
  852.                                 varResult = EscapeString(objMal.Value)
  853.                         Else
  854.                                 varResult = objMal.Value
  855.                         End If
  856.                 Case TYPES.BOOLEAN
  857.                         If objMal.Value Then
  858.                                 varResult = "true"
  859.                         Else
  860.                                 varResult = "false"
  861.                         End If
  862.                 Case TYPES.NIL
  863.                         varResult = "nil"
  864.                 Case TYPES.NUMBER
  865.                         varResult = CStr(objMal.Value)
  866.                 Case TYPES.PROCEDURE
  867.                         varResult = "#<function>"
  868.                 Case TYPES.KEYWORD
  869.                         varResult = objMal.Value
  870.                 Case TYPES.SYMBOL
  871.                         varResult = objMal.Value
  872.                 Case TYPES.ATOM
  873.                         varResult = "(atom " + PrintMalType(objMal.Value, boolReadable) + ")"
  874.                 Case Else
  875.                         Err.Raise vbObjectError, _
  876.                                 "PrintMalType", "Unknown type."
  877.         End Select
  878.         PrintMalType = varResult
  879. End Function
  880. Function EscapeString(strRaw)
  881.         EscapeString = strRaw
  882.         EscapeString = Replace(EscapeString, "\", "\\")
  883.         EscapeString = Replace(EscapeString, vbCrLf, "\n")
  884.         EscapeString = Replace(EscapeString, """", "\""")
  885.         EscapeString = """" & EscapeString & """"
  886. End Function
  887. Function NewEnv(objOuter)
  888.         Dim varRet
  889.         Set varRet = New Environment
  890.         Set varRet.Self = varRet
  891.         Set varRet.Outer = objOuter
  892.         Set NewEnv = varRet
  893. End Function
  894. Class Environment
  895.         Private objOuter, objSelf
  896.         Private objBinds
  897.         Private Sub Class_Initialize()
  898.                 Set objBinds = CreateObject("Scripting.Dictionary")
  899.                 Set objOuter = Nothing
  900.                 Set objSelf = Nothing
  901.         End Sub
  902.         
  903.         Public Property Set Outer(objEnv)
  904.                 Set objOuter = objEnv
  905.         End Property
  906.         Public Property Get Outer()
  907.                 Set Outer = objOuter
  908.         End Property
  909.         Public Property Set Self(objEnv)
  910.                 Set objSelf = objEnv
  911.         End Property
  912.         
  913.         Public Sub Add(varKey, varValue)
  914.                 Set objBinds.Item(varKey.Value) = varValue
  915.         End Sub
  916.         Public Function Find(varKey)
  917.                 Dim varRet
  918.                 If objBinds.Exists(varKey.Value) Then
  919.                         Set varRet = objSelf
  920.                 Else
  921.                         If TypeName(objOuter) <> "Nothing" Then
  922.                                 Set varRet = objOuter.Find(varKey)
  923.                         Else
  924.                                 Err.Raise vbObjectError, _
  925.                                         "Environment", "'" + varKey.Value + "' not found"
  926.                         End If
  927.                 End If
  928.                 Set Find = varRet
  929.         End Function
  930.         
  931.         Public Function [Get](varKey)
  932.                 Dim objEnv, varRet
  933.                 Set objEnv = Find(varKey)
  934.                 If objEnv Is objSelf Then
  935.                         Set varRet = objBinds(varKey.Value)
  936.                 Else
  937.                         Set varRet = objEnv.Get(varKey)
  938.                 End If
  939.                
  940.                 Set [Get] = varRet
  941.         End Function
  942. End Class
  943. Sub CheckArgNum(objArgs, lngArgNum)
  944.         If objArgs.Count - 1 <> lngArgNum Then
  945.                 Err.Raise vbObjectError, _
  946.                         "CheckArgNum", "Wrong number of arguments."
  947.         End IF
  948. End Sub
  949. Sub CheckType(objMal, varType)
  950.         If objMal.Type <> varType Then
  951.                 Err.Raise vbObjectError, _
  952.                         "CheckType", "Wrong argument type."
  953.         End IF
  954. End Sub
  955. Function IsListOrVec(objMal)
  956.         IsListOrVec = _
  957.                 objMal.Type = TYPES.LIST Or _
  958.                 objMal.Type = TYPES.VECTOR
  959. End Function
  960. Sub CheckListOrVec(objMal)
  961.         If Not IsListOrVec(objMal) Then
  962.                 Err.Raise vbObjectError, _
  963.                         "CheckListOrVec", _
  964.                         "Wrong argument type, need a list or a vector."
  965.         End If
  966. End Sub
  967. Dim objNS
  968. Set objNS = NewEnv(Nothing)
  969. Function MAdd(objArgs, objEnv)
  970.         CheckArgNum objArgs, 2
  971.         CheckType objArgs.Item(1), TYPES.NUMBER
  972.         CheckType objArgs.Item(2), TYPES.NUMBER
  973.         Set MAdd = NewMalNum( _
  974.                 objArgs.Item(1).Value + objArgs.Item(2).Value)
  975. End Function
  976. objNS.Add NewMalSym("+"), NewVbsProc("MAdd", False)
  977. Function MSub(objArgs, objEnv)
  978.         CheckArgNum objArgs, 2
  979.         CheckType objArgs.Item(1), TYPES.NUMBER
  980.         CheckType objArgs.Item(2), TYPES.NUMBER
  981.         Set MSub = NewMalNum( _
  982.                 objArgs.Item(1).Value - objArgs.Item(2).Value)
  983. End Function
  984. objNS.Add NewMalSym("-"), NewVbsProc("MSub", False)
  985. Function MMul(objArgs, objEnv)
  986.         CheckArgNum objArgs, 2
  987.         CheckType objArgs.Item(1), TYPES.NUMBER
  988.         CheckType objArgs.Item(2), TYPES.NUMBER
  989.         Set MMul = NewMalNum( _
  990.                 objArgs.Item(1).Value * objArgs.Item(2).Value)
  991. End Function
  992. objNS.Add NewMalSym("*"), NewVbsProc("MMul", False)
  993. Function MDiv(objArgs, objEnv)
  994.         CheckArgNum objArgs, 2
  995.         CheckType objArgs.Item(1), TYPES.NUMBER
  996.         CheckType objArgs.Item(2), TYPES.NUMBER
  997.         Set MDiv = NewMalNum( _
  998.                 objArgs.Item(1).Value \ objArgs.Item(2).Value)
  999. End Function
  1000. objNS.Add NewMalSym("/"), NewVbsProc("MDiv", False)
  1001. Function MList(objArgs, objEnv)
  1002.         Dim varRet
  1003.         Set varRet = NewMalList(Array())
  1004.         Dim i
  1005.         For i = 1 To objArgs.Count - 1
  1006.                 varRet.Add objArgs.Item(i)
  1007.         Next
  1008.         Set MList = varRet
  1009. End Function
  1010. objNS.Add NewMalSym("list"), NewVbsProc("MList", False)
  1011. Function MIsList(objArgs, objEnv)
  1012.         CheckArgNum objArgs, 1
  1013.         Set MIsList = NewMalBool(objArgs.Item(1).Type = TYPES.LIST)
  1014. End Function
  1015. objNS.Add NewMalSym("list?"), NewVbsProc("MIsList", False)
  1016. Function MIsEmpty(objArgs, objEnv)
  1017.         CheckArgNum objArgs, 1
  1018.         CheckListOrVec objArgs.Item(1)
  1019.         Set MIsEmpty = NewMalBool(objArgs.Item(1).Count = 0)
  1020. End Function
  1021. objNS.Add NewMalSym("empty?"), NewVbsProc("MIsEmpty", False)
  1022. Function MCount(objArgs, objEnv)
  1023.         CheckArgNum objArgs, 1
  1024.         If objArgs.Item(1).Type = TYPES.NIL Then
  1025.                 Set MCount = NewMalNum(0)
  1026.         Else
  1027.                 CheckListOrVec objArgs.Item(1)
  1028.                 Set MCount = NewMalNum(objArgs.Item(1).Count)
  1029.         End If
  1030. End Function
  1031. objNS.Add NewMalSym("count"), NewVbsProc("MCount", False)
  1032. Function MEqual(objArgs, objEnv)
  1033.         Dim varRet
  1034.         CheckArgNum objArgs, 2
  1035.         Dim boolResult, i
  1036.         If IsListOrVec(objArgs.Item(1)) And _
  1037.                 IsListOrVec(objArgs.Item(2)) Then
  1038.                 If objArgs.Item(1).Count <> objArgs.Item(2).Count Then
  1039.                         Set varRet = NewMalBool(False)
  1040.                 Else
  1041.                         boolResult = True
  1042.                         For i = 0 To objArgs.Item(1).Count - 1
  1043.                                 boolResult = boolResult And _
  1044.                                         MEqual(NewMalList(Array(Nothing, _
  1045.                                         objArgs.Item(1).Item(i), _
  1046.                                         objArgs.Item(2).Item(i))), objEnv).Value
  1047.                         Next
  1048.                         Set varRet = NewMalBool(boolResult)        
  1049.                 End If
  1050.         Else
  1051.                 If objArgs.Item(1).Type <> objArgs.Item(2).Type Then
  1052.                         Set varRet = NewMalBool(False)
  1053.                 Else
  1054.                         Select Case objArgs.Item(1).Type
  1055.                                 Case TYPES.HASHMAP
  1056.                                         'Err.Raise vbObjectError, _
  1057.                                         '        "MEqual", "Not implement yet~"
  1058.                                         If UBound(objArgs.Item(1).Keys) <> UBound(objArgs.Item(2).Keys) Then
  1059.                                                 Set varRet = NewMalBool(False)
  1060.                                                 Set MEqual = varRet
  1061.                                                 Exit Function
  1062.                                         End If
  1063.                                        
  1064.                                         boolResult = True
  1065.                                         For Each i In objArgs.Item(1).Keys
  1066.                                                 If Not objArgs.Item(2).Exists(i) Then
  1067.                                                         Set varRet = NewMalBool(False)
  1068.                                                         Set MEqual = varRet
  1069.                                                         Exit Function
  1070.                                                 End If
  1071.                                                 boolResult = boolResult And _
  1072.                                                         MEqual(NewMalList(Array(Nothing, objArgs.Item(1).Item(i), objArgs.Item(2).Item(i))), objEnv).Value
  1073.                                         Next
  1074.                                         Set varRet = NewMalBool(boolResult)        
  1075.                                        
  1076.                                 Case Else
  1077.                                         Set varRet = NewMalBool( _
  1078.                                                 objArgs.Item(1).Value = objArgs.Item(2).Value)
  1079.                         End Select
  1080.                 End If
  1081.         End If
  1082.         Set MEqual = varRet
  1083. End Function
  1084. objNS.Add NewMalSym("="), NewVbsProc("MEqual", False)
  1085. Function MGreater(objArgs, objEnv)
  1086.         Dim varRet
  1087.         CheckArgNum objArgs, 2
  1088.         CheckType objArgs.Item(1), TYPES.NUMBER
  1089.         CheckType objArgs.Item(2), TYPES.NUMBER
  1090.         Set varRet = NewMalBool( _
  1091.                 objArgs.Item(1).Value > objArgs.Item(2).Value)
  1092.         Set MGreater = varRet
  1093. End Function
  1094. objNS.Add NewMalSym(">"), NewVbsProc("MGreater", False)
  1095. Function MPrStr(objArgs, objEnv)
  1096.         Dim varRet
  1097.         Dim strRet
  1098.         strRet = ""
  1099.         Dim i
  1100.         If objArgs.Count - 1 >= 1 Then
  1101.                 strRet = PrintMalType(objArgs.Item(1), True)
  1102.         End If
  1103.         For i = 2 To objArgs.Count - 1
  1104.                 strRet = strRet + " " + _
  1105.                         PrintMalType(objArgs.Item(i), True)
  1106.         Next
  1107.         Set varRet = NewMalStr(strRet)
  1108.         Set MPrStr = varRet
  1109. End Function
  1110. objNS.Add NewMalSym("pr-str"), NewVbsProc("MPrStr", False)
  1111. Function MStr(objArgs, objEnv)
  1112.         Dim varRet
  1113.         Dim strRet
  1114.         strRet = ""
  1115.         Dim i
  1116.         For i = 1 To objArgs.Count - 1
  1117.                 strRet = strRet + _
  1118.                         PrintMalType(objArgs.Item(i), False)
  1119.         Next
  1120.         Set varRet = NewMalStr(strRet)
  1121.         Set MStr = varRet
  1122. End Function
  1123. objNS.Add NewMalSym("str"), NewVbsProc("MStr", False)
  1124. Function MPrn(objArgs, objEnv)
  1125.         Dim varRet
  1126.         Dim objStr
  1127.         Set objStr = MPrStr(objArgs, objEnv)
  1128.         WScript.StdOut.WriteLine objStr.Value
  1129.         Set varRet = NewMalNil()
  1130.         Set MPrn = varRet
  1131. End Function
  1132. objNS.Add NewMalSym("prn"), NewVbsProc("MPrn", False)
  1133. Function MPrintln(objArgs, objEnv)
  1134.         Dim varRet
  1135.         Dim strRes
  1136.         strRes = ""
  1137.         Dim i
  1138.         If objArgs.Count - 1 >= 1 Then
  1139.                 strRes = PrintMalType(objArgs.Item(1), False)
  1140.         End If
  1141.         For i = 2 To objArgs.Count - 1
  1142.                 strRes = strRes + " " + _
  1143.                         PrintMalType(objArgs.Item(i), False)
  1144.         Next
  1145.         WScript.StdOut.WriteLine strRes
  1146.         Set varRet = NewMalNil()
  1147.         Set MPrintln = varRet
  1148. End Function
  1149. objNS.Add NewMalSym("println"), NewVbsProc("MPrintln", False)
  1150. Sub InitBuiltIn()
  1151.         REP "(def! not (fn* [bool] (if bool false true)))"
  1152.         REP "(def! <= (fn* [a b] (not (> a b))))"
  1153.         REP "(def! < (fn* [a b] (> b a)))"
  1154.         REP "(def! >= (fn* [a b] (not (> b a))))"
  1155.         REP "(def! load-file (fn* (f) (eval (read-string (str ""(do "" (slurp f) ""\nnil)"")))))"
  1156.         REP "(def! cons (fn* [a b] (concat (list a) b)))"
  1157.         REP "(def! nil? (fn* [x] (= x nil)))"
  1158.         REP "(def! true? (fn* [x] (= x true)))"
  1159.         REP "(def! false? (fn* [x] (= x false)))"
  1160.         REP "(def! vector (fn* [& args] (vec args)))"
  1161.         REP "(def! vals (fn* [hmap] (map (fn* [key] (get hmap key)) (keys hmap))))"
  1162.         REP "(def! *host-language* ""VBScript"")"
  1163. End Sub
  1164. Function MReadStr(objArgs, objEnv)
  1165.         Dim varRes
  1166.         CheckArgNum objArgs, 1
  1167.         CheckType objArgs.Item(1), TYPES.STRING
  1168.         Set varRes = ReadString(objArgs.Item(1).Value)
  1169.         If TypeName(varRes) = "Nothing" Then
  1170.                 Set varRes = NewMalNil()
  1171.         End If
  1172.         Set MReadStr = varRes
  1173. End Function
  1174. objNS.Add NewMalSym("read-string"), NewVbsProc("MReadStr", False)
  1175. Function MSlurp(objArgs, objEnv)
  1176.         Dim varRes
  1177.         CheckArgNum objArgs, 1
  1178.         CheckType objArgs.Item(1), TYPES.STRING
  1179.         Dim strRes
  1180.         With CreateObject("Scripting.FileSystemObject")
  1181.                 strRes = .OpenTextFile( _
  1182.                         .GetParentFolderName( _
  1183.                         .GetFile(WScript.ScriptFullName)) & _
  1184.                         "\" & objArgs.Item(1).Value).ReadAll
  1185.         End With
  1186.         Set varRes = NewMalStr(strRes)
  1187.         Set MSlurp = varRes
  1188. End Function
  1189. objNS.Add NewMalSym("slurp"), NewVbsProc("MSlurp", False)
  1190. Function MAtom(objArgs, objEnv)
  1191.         Dim varRes
  1192.         CheckArgNum objArgs, 1
  1193.         Set varRes = NewMalAtom(objArgs.Item(1))
  1194.         Set MAtom = varRes
  1195. End Function
  1196. objNS.Add NewMalSym("atom"), NewVbsProc("MAtom", False)
  1197. Function MIsAtom(objArgs, objEnv)
  1198.         Dim varRes
  1199.         CheckArgNum objArgs, 1
  1200.         Set varRes = NewMalBool(objArgs.Item(1).Type = TYPES.ATOM)
  1201.         Set MIsAtom = varRes
  1202. End Function
  1203. objNS.Add NewMalSym("atom?"), NewVbsProc("MIsAtom", False)
  1204. Function MDeref(objArgs, objEnv)
  1205.         Dim varRes
  1206.         CheckArgNum objArgs, 1
  1207.         CheckType objArgs.Item(1), TYPES.ATOM
  1208.         Set varRes = objArgs.Item(1).Value
  1209.         Set MDeref = varRes
  1210. End Function
  1211. objNS.Add NewMalSym("deref"), NewVbsProc("MDeref", False)
  1212. Function MReset(objArgs, objEnv)
  1213.         Dim varRes
  1214.         CheckArgNum objArgs, 2
  1215.         CheckType objArgs.Item(1), TYPES.ATOM
  1216.         objArgs.Item(1).Reset objArgs.Item(2)
  1217.         Set varRes = objArgs.Item(2)
  1218.         Set MReset = varRes
  1219. End Function
  1220. objNS.Add NewMalSym("reset!"), NewVbsProc("MReset", False)
  1221. Function MSwap(objArgs, objEnv)
  1222.         Dim varRes
  1223.         If objArgs.Count - 1 < 2 Then
  1224.                 Err.Raise vbObjectError, _
  1225.                         "MSwap", "Need more arguments."
  1226.         End If
  1227.         Dim objAtom, objFn
  1228.         Set objAtom = objArgs.Item(1)
  1229.         CheckType objAtom, TYPES.ATOM
  1230.         Set objFn = objArgs.Item(2)
  1231.         CheckType objFn, TYPES.PROCEDURE
  1232.         Dim objProg
  1233.         Set objProg = NewMalList(Array(objFn))
  1234.         objProg.Add objAtom.Value
  1235.         Dim i
  1236.         For i = 3 To objArgs.Count - 1
  1237.                 objProg.Add objArgs.Item(i)
  1238.         Next
  1239.         objAtom.Reset objFn.ApplyWithoutEval(objProg, objEnv)
  1240.         Set varRes = objAtom.Value
  1241.         Set MSwap = varRes
  1242. End Function
  1243. objNS.Add NewMalSym("swap!"), NewVbsProc("MSwap", False)
  1244. Function MConcat(objArgs, objEnv)
  1245.         Dim varRes
  1246.         Dim i, j
  1247.         Set varRes = NewMalList(Array())
  1248.         For i = 1 To objArgs.Count - 1
  1249.                 If Not IsListOrVec(objArgs.Item(i)) Then
  1250.                         Err.Raise vbObjectError, _
  1251.                                 "MConcat", "Invaild argument(s)."
  1252.                 End If
  1253.                
  1254.                 For j = 0 To objArgs.Item(i).Count - 1
  1255.                         varRes.Add objArgs.Item(i).Item(j)
  1256.                 Next
  1257.         Next
  1258.         Set MConcat = varRes
  1259. End Function
  1260. objNS.Add NewMalSym("concat"), NewVbsProc("MConcat", False)
  1261. Function MVec(objArgs, objEnv)
  1262.         Dim varRes
  1263.         CheckArgNum objArgs, 1
  1264.         CheckListOrVec objArgs.Item(1)
  1265.         Set varRes = NewMalVec(Array())
  1266.         Dim i
  1267.         For i = 0 To objArgs.Item(1).Count - 1
  1268.                 varRes.Add objArgs.Item(1).Item(i)
  1269.         Next
  1270.         Set MVec = varRes
  1271. End Function
  1272. objNS.Add NewMalSym("vec"), NewVbsProc("MVec", False)
  1273. Function MNth(objArgs, objEnv)
  1274.         Dim varRes
  1275.         CheckArgNum objArgs, 2
  1276.         CheckListOrVec objArgs.Item(1)
  1277.         CheckType objArgs.Item(2), TYPES.NUMBER
  1278.         If objArgs.Item(2).Value < objArgs.Item(1).Count Then
  1279.                 Set varRes = objArgs.Item(1).Item(objArgs.Item(2).Value)
  1280.         Else
  1281.                 Err.Raise vbObjectError, _
  1282.                         "MNth", "Index out of bounds."
  1283.         End If
  1284.         Set MNth = varRes
  1285. End Function
  1286. objNS.Add NewMalSym("nth"), NewVbsProc("MNth", False)
  1287. Function MFirst(objArgs, objEnv)
  1288.         Dim varRes
  1289.         CheckArgNum objArgs, 1
  1290.         
  1291.         If objArgs.Item(1).Type = TYPES.NIL Then
  1292.                 Set varRes = NewMalNil()
  1293.                 Set MFirst = varRes
  1294.                 Exit Function
  1295.         End If
  1296.         CheckListOrVec objArgs.Item(1)
  1297.         If objArgs.Item(1).Count < 1 Then
  1298.                 Set varRes = NewMalNil()
  1299.         Else
  1300.                 Set varRes = objArgs.Item(1).Item(0)
  1301.         End If
  1302.         Set MFirst = varRes
  1303. End Function
  1304. objNS.Add NewMalSym("first"), NewVbsProc("MFirst", False)
  1305. Function MRest(objArgs, objEnv)
  1306.         Dim varRes
  1307.         CheckArgNum objArgs, 1
  1308.         
  1309.         If objArgs.Item(1).Type = TYPES.NIL Then
  1310.                 Set varRes = NewMalList(Array())
  1311.                 Set MRest = varRes
  1312.                 Exit Function
  1313.         End If
  1314.         Dim objList
  1315.         Set objList = objArgs.Item(1)
  1316.         CheckListOrVec objList
  1317.         Set varRes = NewMalList(Array())
  1318.         Dim i
  1319.         For i = 1 To objList.Count - 1
  1320.                 varRes.Add objList.Item(i)
  1321.         Next
  1322.         
  1323.         Set MRest = varRes
  1324. End Function
  1325. objNS.Add NewMalSym("rest"), NewVbsProc("MRest", False)
  1326. Sub InitMacro()
  1327.         REP "(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw ""odd number of forms to cond"")) (cons'cond (rest (rest xs)))))))"
  1328.         'REP "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))"
  1329.         REP "(def! *gensym-counter* (atom 0))"
  1330.         REP "(def! gensym (fn* [] (symbol (str ""G__"" (swap! *gensym-counter* (fn* [x] (+ 1 x)))))))"
  1331.         REP "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) (let* (condvar (gensym)) `(let* (~condvar ~(first xs)) (if ~condvar ~condvar (or ~@(rest xs)))))))))"
  1332. End Sub
  1333. Class MalException
  1334.         Private objDict
  1335.         Private Sub Class_Initialize
  1336.                 Set objDict = CreateObject("Scripting.Dictionary")
  1337.         End Sub
  1338.         Public Sub Add(varKey, varValue)
  1339.                 objDict.Add varKey, varValue
  1340.         End Sub
  1341.         Public Function Item(varKey)
  1342.                 Set Item = objDict.Item(varKey)
  1343.         End Function
  1344.         Public Sub Remove(varKey)
  1345.                 objDict.Remove varKey
  1346.         End Sub
  1347. End Class
  1348. Dim objExceptions
  1349. Set objExceptions = New MalException
  1350. Function MThrow(objArgs, objEnv)
  1351.         CheckArgNum objArgs, 1
  1352.         Dim strRnd
  1353.         strRnd = CStr(Rnd())
  1354.         objExceptions.Add strRnd, objArgs.Item(1)
  1355.         Err.Raise vbObjectError, _
  1356.                 "MThrow", strRnd
  1357. End Function
  1358. objNS.Add NewMalSym("throw"), NewVbsProc("MThrow", False)
  1359. Function MApply(objArgs, objEnv)
  1360.         Dim varRes
  1361.         If objArgs.Count - 1 < 2 Then
  1362.                 Err.Raise vbObjectError, _
  1363.                         "MApply", "Need more arguments."
  1364.         End If
  1365.         
  1366.         Dim objFn
  1367.         Set objFn = objArgs.Item(1)
  1368.         CheckType objFn, TYPES.PROCEDURE
  1369.         If objFn.IsSpecial Or objFn.IsMacro Then
  1370.                 Err.Raise vbObjectError, _
  1371.                         "MApply", "Need a function."
  1372.         End If
  1373.         Dim objAST
  1374.         Set objAST = NewMalList(Array(objFn))
  1375.         Dim i
  1376.         For i = 2 To objArgs.Count - 2
  1377.                 objAST.Add objArgs.Item(i)
  1378.         Next
  1379.         Dim objSeq
  1380.         Set objSeq = objArgs.Item(objArgs.Count - 1)
  1381.         CheckListOrVec objSeq
  1382.         For i = 0 To objSeq.Count - 1
  1383.                 objAST.Add objSeq.Item(i)
  1384.         Next
  1385.         
  1386.         Set varRes = objFn.ApplyWithoutEval(objAST, objEnv)
  1387.         Set MApply = varRes
  1388. End Function
  1389. objNS.Add NewMalSym("apply"), NewVbsProc("MApply", False)
  1390. Function MMap(objArgs, objEnv)
  1391.         Dim varRes
  1392.         CheckArgNum objArgs, 2
  1393.         Dim objFn, objSeq
  1394.         Set objFn = objArgs.Item(1)
  1395.         Set objSeq = objArgs.Item(2)
  1396.         CheckType objFn, TYPES.PROCEDURE
  1397.         CheckListOrVec objSeq
  1398.         If objFn.IsSpecial Or objFn.IsMacro Then
  1399.                 Err.Raise vbObjectError, _
  1400.                         "MApply", "Need a function."
  1401.         End If
  1402.         Set varRes = NewMalList(Array())
  1403.         Dim i
  1404.         For i = 0 To objSeq.Count - 1
  1405.                 varRes.Add objFn.ApplyWithoutEval(NewMalList(Array( _
  1406.                         objFn, objSeq.Item(i))), objEnv)
  1407.         Next
  1408.         Set MMap = varRes
  1409. End Function
  1410. objNS.Add NewMalSym("map"), NewVbsProc("MMap", False)
  1411. Function MIsSymbol(objArgs, objEnv)
  1412.         Dim varRes
  1413.         CheckArgNum objArgs, 1
  1414.         Set varRes = NewMalBool(objArgs.Item(1).Type = TYPES.SYMBOL)
  1415.         Set MIsSymbol = varRes
  1416. End Function
  1417. objNS.Add NewMalSym("symbol?"), NewVbsProc("MIsSymbol", False)
  1418. Function MSymbol(objArgs, objEnv)
  1419.         Dim varRes
  1420.         CheckArgNum objArgs, 1
  1421.         CheckType objArgs.Item(1), TYPES.STRING
  1422.         Set varRes = NewMalSym(objArgs.Item(1).Value)
  1423.         Set MSymbol = varRes
  1424. End Function
  1425. objNS.Add NewMalSym("symbol"), NewVbsProc("MSymbol", False)
  1426. Function MKeyword(objArgs, objEnv)
  1427.         Dim varRes
  1428.         CheckArgNum objArgs, 1
  1429.         Select Case objArgs.Item(1).Type
  1430.                 Case TYPES.STRING
  1431.                         Set varRes = NewMalKwd(":" + objArgs.Item(1).Value)
  1432.                 Case TYPES.KEYWORD
  1433.                         Set varRes = objArgs.Item(1)
  1434.                 Case Else
  1435.                         Err.Raise vbObjectError, _
  1436.                                 "MKeyword", "Unexpect argument(s)."
  1437.         End Select
  1438.         Set MKeyword = varRes
  1439. End Function
  1440. objNS.Add NewMalSym("keyword"), NewVbsProc("MKeyword", False)
  1441. Function MIsKeyword(objArgs, objEnv)
  1442.         Dim varRes
  1443.         CheckArgNum objArgs, 1
  1444.         Set varRes = NewMalBool(objArgs.Item(1).Type = TYPES.KEYWORD)
  1445.         Set MIsKeyword = varRes
  1446. End Function
  1447. objNS.Add NewMalSym("keyword?"), NewVbsProc("MIsKeyword", False)
  1448. Function MIsSeq(objArgs, objEnv)
  1449.         Dim varRes
  1450.         CheckArgNum objArgs, 1
  1451.         Set varRes = NewMalBool( _
  1452.                 objArgs.Item(1).Type = TYPES.LIST Or _
  1453.                 objArgs.Item(1).Type = TYPES.VECTOR)
  1454.         Set MIsSeq = varRes
  1455. End Function
  1456. objNS.Add NewMalSym("sequential?"), NewVbsProc("MIsSeq", False)
  1457. Function MIsVec(objArgs, objEnv)
  1458.         Dim varRes
  1459.         CheckArgNum objArgs, 1
  1460.         Set varRes = NewMalBool(objArgs.Item(1).Type = TYPES.VECTOR)
  1461.         Set MIsVec = varRes
  1462. End Function
  1463. objNS.Add NewMalSym("vector?"), NewVbsProc("MIsVec", False)
  1464. Function MIsMap(objArgs, objEnv)
  1465.         Dim varRes
  1466.         CheckArgNum objArgs, 1
  1467.         Set varRes = NewMalBool(objArgs.Item(1).Type = TYPES.HASHMAP)
  1468.         Set MIsMap = varRes
  1469. End Function
  1470. objNS.Add NewMalSym("map?"), NewVbsProc("MIsMap", False)
  1471. Function MHashMap(objArgs, objEnv)
  1472.         Dim varRes
  1473.         If objArgs.Count Mod 2 <> 1 Then
  1474.                 Err.Raise vbObjectError, _
  1475.                         "MHashMap", "Unexpect argument(s)."
  1476.         End If
  1477.         Set varRes = NewMalMap(Array(), Array())
  1478.         Dim i
  1479.         For i = 1 To objArgs.Count - 1 Step 2
  1480.                 varRes.Add objArgs.Item(i), objArgs.Item(i + 1)
  1481.         Next
  1482.         Set MHashMap = varRes
  1483. End Function
  1484. objNS.Add NewMalSym("hash-map"), NewVbsProc("MHashMap", False)
  1485. Function MAssoc(objArgs, objEnv)
  1486.         Dim varRes
  1487.         If objArgs.Count - 1 < 3 Or objArgs.Count Mod 2 <> 0 Then
  1488.                 Err.Raise vbObjectError, _
  1489.                         "MHashMap", "Unexpect argument(s)."
  1490.         End If
  1491.         
  1492.         Dim objMap
  1493.         Set objMap = objArgs.Item(1)
  1494.         CheckType objMap, TYPES.HASHMAP
  1495.         Dim i
  1496.         Set varRes = NewMalMap(Array(), Array())
  1497.         For Each i In objMap.Keys
  1498.                 varRes.Add i, objMap.Item(i)
  1499.         Next
  1500.         For i = 2 To objArgs.Count - 1 Step 2
  1501.                 varRes.Add objArgs.Item(i), objArgs.Item(i + 1)
  1502.         Next
  1503.         Set MAssoc = varRes
  1504. End Function
  1505. objNS.Add NewMalSym("assoc"), NewVbsProc("MAssoc", False)
  1506. Function MGet(objArgs, objEnv)
  1507.         Dim varRes
  1508.         CheckArgNum objArgs, 2
  1509.         
  1510.         If objArgs.Item(1).Type = TYPES.NIL Then
  1511.                 Set varRes = NewMalNil()
  1512.         Else
  1513.                 CheckType objArgs.Item(1), TYPES.HASHMAP
  1514.                 If objArgs.Item(1).Exists(objArgs.Item(2)) Then
  1515.                         Set varRes = objArgs.Item(1).Item(objArgs.Item(2))
  1516.                 Else
  1517.                         Set varRes = NewMalNil()
  1518.                 End If
  1519.         End If
  1520.         
  1521.         Set MGet = varRes
  1522. End Function
  1523. objNS.Add NewMalSym("get"), NewVbsProc("MGet", False)
  1524. Function MDissoc(objArgs, objEnv)
  1525.         Dim varRes
  1526.         'CheckArgNum objArgs, 2
  1527.         CheckType objArgs.Item(1), TYPES.HASHMAP
  1528.         
  1529.         If objArgs.Item(1).Exists(objArgs.Item(2)) Then
  1530.                 Set varRes = NewMalMap(Array(), Array())
  1531.                
  1532.                 Dim i
  1533.                 Dim j, boolFlag
  1534.                 For Each i In objArgs.Item(1).Keys
  1535.                         boolFlag = True
  1536.                         For j = 2 To objArgs.Count - 1
  1537.                                 If i.Type = objArgs.Item(j).Type And _
  1538.                                         i.Value = objArgs.Item(j).Value Then
  1539.                                         boolFlag = False
  1540.                                 End If
  1541.                         Next
  1542.                         If boolFlag Then
  1543.                                 varRes.Add i, objArgs.Item(1).Item(i)
  1544.                         End If
  1545.                 Next
  1546.         Else
  1547.                 Set varRes = objArgs.Item(1)
  1548.         End If
  1549.         Set MDissoc = varRes
  1550. End Function
  1551. objNS.Add NewMalSym("dissoc"), NewVbsProc("MDissoc", False)
  1552. Function MKeys(objArgs, objEnv)
  1553.         CheckArgNum objArgs, 1
  1554.         CheckType objArgs.Item(1), TYPES.HASHMAP
  1555.         Set MKeys = NewMalList(objArgs.Item(1).Keys)
  1556. End Function
  1557. objNS.Add NewMalSym("keys"), NewVbsProc("MKeys", False)
  1558. Function MIsContains(objArgs, objEnv)
  1559.         CheckArgNum objArgs, 2
  1560.         CheckType objArgs.Item(1), TYPES.HASHMAP
  1561.         Set MIsContains = NewMalBool(objArgs.Item(1).Exists(objArgs.Item(2)))
  1562. End Function
  1563. objNS.Add NewMalSym("contains?"), NewVbsProc("MIsContains", False)
  1564. Function MReadLine(objArgs, objEnv)
  1565.         Dim varRes
  1566.         CheckArgNum objArgs, 1
  1567.         CheckType objArgs.Item(1), TYPES.STRING
  1568.         Dim strInput
  1569.         WScript.StdOut.Write objArgs.Item(1).Value
  1570.         On Error Resume Next
  1571.                 strInput = WScript.StdIn.ReadLine()
  1572.                 If Err.Number <> 0 Then
  1573.                         Set varRes = NewMalNil()
  1574.                 Else
  1575.                         Set varRes = NewMalStr(strInput)
  1576.                 End If
  1577.         On Error Goto 0
  1578.         Set MReadLine = varRes
  1579. End Function
  1580. objNS.Add NewMalSym("readline"), NewVbsProc("MReadLine", False)
  1581. Function MTimeMs(objArgs, objEnv)
  1582.         Set MTimeMs = NewMalNum(CLng(Timer * 1000))
  1583. End Function
  1584. objNS.Add NewMalSym("time-ms"), NewVbsProc("MTimeMs", False)
  1585. Function MIsStr(objArgs, objEnv)
  1586.         CheckArgNum objArgs, 1
  1587.         Set MIsStr = NewMalBool(objArgs.Item(1).Type = TYPES.STRING)
  1588. End Function
  1589. objNS.Add NewMalSym("string?"), NewVbsProc("MIsStr", False)
  1590. Function MIsNum(objArgs, objEnv)
  1591.         CheckArgNum objArgs, 1
  1592.         Set MIsNum = NewMalBool(objArgs.Item(1).Type = TYPES.NUMBER)
  1593. End Function
  1594. objNS.Add NewMalSym("number?"), NewVbsProc("MIsNum", False)
  1595. Function MIsFn(objArgs, objEnv)
  1596.         CheckArgNum objArgs, 1
  1597.         Dim varRes
  1598.         varRes = objArgs.Item(1).Type = TYPES.PROCEDURE
  1599.         If varRes Then
  1600.                 varRes = (Not objArgs.Item(1).IsMacro) And _
  1601.                         (Not objArgs.Item(1).IsSpecial)
  1602.         End If
  1603.         
  1604.         Set MIsFn = NewMalBool(varRes)
  1605. End Function
  1606. objNS.Add NewMalSym("fn?"), NewVbsProc("MIsFn", False)
  1607. Function MIsMacro(objArgs, objEnv)
  1608.         CheckArgNum objArgs, 1
  1609.         Dim varRes
  1610.         varRes = objArgs.Item(1).Type = TYPES.PROCEDURE
  1611.         If varRes Then
  1612.                 varRes = objArgs.Item(1).IsMacro And _
  1613.                         (Not objArgs.Item(1).IsSpecial)
  1614.         End If
  1615.         
  1616.         Set MIsMacro = NewMalBool(varRes)
  1617. End Function
  1618. objNS.Add NewMalSym("macro?"), NewVbsProc("MIsMacro", False)
  1619. Function MMeta(objArgs, objEnv)
  1620.         CheckArgNum objArgs, 1
  1621.         'CheckType objArgs.Item(1), TYPES.PROCEDURE
  1622.         Dim varRes
  1623.         Set varRes = GetMeta(objArgs.Item(1))
  1624.         Set MMeta = varRes
  1625. End Function
  1626. objNS.Add NewMalSym("meta"), NewVbsProc("MMeta", False)
  1627. Function MWithMeta(objArgs, objEnv)
  1628.         CheckArgNum objArgs, 2
  1629.         'CheckType objArgs.Item(1), TYPES.PROCEDURE
  1630.         Dim varRes
  1631.         Set varRes = SetMeta(objArgs.Item(1), objArgs.Item(2))
  1632.         Set MWithMeta = varRes
  1633. End Function
  1634. objNS.Add NewMalSym("with-meta"), NewVbsProc("MWithMeta", False)
  1635. Function MConj(objArgs, objEnv)
  1636.         If objArgs.Count - 1 < 1 Then
  1637.                 Err.Raise vbObjectError, _
  1638.                         "MConj", "Need more arguments."
  1639.         End If
  1640.         Dim varRes
  1641.         Dim objSeq
  1642.         Set objSeq = objArgs.Item(1)
  1643.         Dim i
  1644.         Select Case objSeq.Type
  1645.                 Case TYPES.LIST
  1646.                         Set varRes = NewMalList(Array())
  1647.                         For i = objArgs.Count - 1 To 2 Step -1
  1648.                                 varRes.Add objArgs.Item(i)
  1649.                         Next
  1650.                         For i = 0 To objSeq.Count - 1
  1651.                                 varRes.Add objSeq.Item(i)
  1652.                         Next
  1653.                 Case TYPES.VECTOR
  1654.                         Set varRes = NewMalVec(Array())
  1655.                         For i = 0 To objSeq.Count - 1
  1656.                                 varRes.Add objSeq.Item(i)
  1657.                         Next
  1658.                         For i = 2 To objArgs.Count - 1
  1659.                                 varRes.Add objArgs.Item(i)
  1660.                         Next
  1661.                 Case Else        
  1662.                         Err.Raise vbObjectError, _
  1663.                                 "MConj", "Unexpect argument type."
  1664.         End Select
  1665.         Set MConj = varRes
  1666. End Function
  1667. objNS.Add NewMalSym("conj"), NewVbsProc("MConj", False)
  1668. Function MSeq(objArgs, objEnv)
  1669.         CheckArgNum objArgs, 1
  1670.         Dim objSeq
  1671.         Set objSeq = objArgs.Item(1)
  1672.         Dim varRes
  1673.         Dim i
  1674.         Select Case objSeq.Type
  1675.                 Case TYPES.STRING
  1676.                         If objSeq.Value = "" Then
  1677.                                 Set varRes = NewMalNil()
  1678.                         Else
  1679.                                 Set varRes = NewMalList(Array())
  1680.                                 For i = 1 To Len(objSeq.Value)
  1681.                                         varRes.Add NewMalStr(Mid(objSeq.Value, i, 1))
  1682.                                 Next
  1683.                         End If
  1684.                 Case TYPES.LIST
  1685.                         If objSeq.Count = 0 Then
  1686.                                 Set varRes = NewMalNil()
  1687.                         Else
  1688.                                 Set varRes = objSeq
  1689.                         End If
  1690.                 Case TYPES.VECTOR
  1691.                         If objSeq.Count = 0 Then
  1692.                                 Set varRes = NewMalNil()
  1693.                         Else
  1694.                                 Set varRes = NewMalList(Array())
  1695.                                 For i = 0 To objSeq.Count - 1
  1696.                                         varRes.Add objSeq.Item(i)
  1697.                                 Next
  1698.                         End If
  1699.                 Case TYPES.NIL
  1700.                         Set varRes = NewMalNil()
  1701.                 Case Else
  1702.                         Err.Raise vbObjectError, _
  1703.                                 "MSeq", "Unexpect argument type."
  1704.         End Select
  1705.         Set MSeq = varRes
  1706. End Function
  1707. objNS.Add NewMalSym("seq"), NewVbsProc("MSeq", False)
  1708. Class TailCall
  1709.         Public objMalType
  1710.         Public objEnv
  1711. End Class
  1712. Function EvalLater(objMal, objEnv)
  1713.         Dim varRes
  1714.         Set varRes = New TailCall
  1715.         Set varRes.objMalType = objMal
  1716.         Set varRes.objEnv = objEnv
  1717.         Set EvalLater = varRes
  1718. End Function
  1719. Function MDef(objArgs, objEnv)
  1720.         Dim varRet
  1721.         CheckArgNum objArgs, 2
  1722.         CheckType objArgs.Item(1), TYPES.SYMBOL
  1723.         Set varRet = Evaluate(objArgs.Item(2), objEnv)
  1724.         objEnv.Add objArgs.Item(1), varRet
  1725.         Set MDef = varRet
  1726. End Function
  1727. objNS.Add NewMalSym("def!"), NewVbsProc("MDef", True)
  1728. Function MLet(objArgs, objEnv)
  1729.         Dim varRet
  1730.         CheckArgNum objArgs, 2
  1731.         Dim objBinds
  1732.         Set objBinds = objArgs.Item(1)
  1733.         CheckListOrVec objBinds
  1734.         
  1735.         If objBinds.Count Mod 2 <> 0 Then
  1736.                 Err.Raise vbObjectError, _
  1737.                         "MLet", "Wrong argument count."
  1738.         End If
  1739.         Dim objNewEnv
  1740.         Set objNewEnv = NewEnv(objEnv)
  1741.         Dim i, objSym
  1742.         For i = 0 To objBinds.Count - 1 Step 2
  1743.                 Set objSym = objBinds.Item(i)
  1744.                 CheckType objSym, TYPES.SYMBOL
  1745.                 objNewEnv.Add objSym, Evaluate(objBinds.Item(i + 1), objNewEnv)
  1746.         Next
  1747.         Set varRet = EvalLater(objArgs.Item(2), objNewEnv)
  1748.         Set MLet = varRet
  1749. End Function
  1750. objNS.Add NewMalSym("let*"), NewVbsProc("MLet", True)
  1751. Function MDo(objArgs, objEnv)
  1752.         Dim varRet, i
  1753.         If objArgs.Count - 1 < 1 Then
  1754.                 Err.Raise vbObjectError, _
  1755.                         "MDo", "Need more arguments."
  1756.         End If
  1757.         For i = 1 To objArgs.Count - 2
  1758.                 Call Evaluate(objArgs.Item(i), objEnv)
  1759.         Next
  1760.         Set varRet = EvalLater( _
  1761.                 objArgs.Item(objArgs.Count - 1), _
  1762.                 objEnv)
  1763.         Set MDo = varRet
  1764. End Function
  1765. objNS.Add NewMalSym("do"), NewVbsProc("MDo", True)
  1766. Function MIf(objArgs, objEnv)
  1767.         Dim varRet
  1768.         If objArgs.Count - 1 <> 3 And _
  1769.                 objArgs.Count - 1 <> 2 Then
  1770.                 Err.Raise vbObjectError, _
  1771.                         "MIf", "Wrong number of arguments."
  1772.         End If
  1773.         Dim objCond
  1774.         Set objCond = Evaluate(objArgs.Item(1), objEnv)
  1775.         Dim boolCond
  1776.         If objCond.Type = TYPES.BOOLEAN Then
  1777.                 boolCond = objCond.Value
  1778.         Else
  1779.                 boolCond = True
  1780.         End If
  1781.         boolCond = (boolCond And objCond.Type <> TYPES.NIL)
  1782.         If boolCond Then
  1783.                 Set varRet = EvalLater(objArgs.Item(2), objEnv)
  1784.         Else
  1785.                 If objArgs.Count - 1 = 3 Then
  1786.                         Set varRet = EvalLater(objArgs.Item(3), objEnv)
  1787.                 Else
  1788.                         Set varRet = NewMalNil()
  1789.                 End If
  1790.         End If
  1791.         Set MIf = varRet
  1792. End Function
  1793. objNS.Add NewMalSym("if"), NewVbsProc("MIf", True)
  1794. Function MFn(objArgs, objEnv)
  1795.         Dim varRet
  1796.         CheckArgNum objArgs, 2
  1797.         Dim objParams, objCode
  1798.         Set objParams = objArgs.Item(1)
  1799.         CheckListOrVec objParams
  1800.         Set objCode = objArgs.Item(2)
  1801.         
  1802.         Dim i
  1803.         For i = 0 To objParams.Count - 1
  1804.                 CheckType objParams.Item(i), TYPES.SYMBOL
  1805.         Next
  1806.         Set varRet = NewMalProc(objParams, objCode, objEnv)
  1807.         Set MFn = varRet
  1808. End Function
  1809. objNS.Add NewMalSym("fn*"), NewVbsProc("MFn", True)
  1810. Function MEval(objArgs, objEnv)
  1811.         Dim varRes
  1812.         CheckArgNum objArgs, 1
  1813.         Set varRes = Evaluate(objArgs.Item(1), objEnv)
  1814.         Set varRes = EvalLater(varRes, objNS)
  1815.         Set MEval = varRes
  1816. End Function
  1817. objNS.Add NewMalSym("eval"), NewVbsProc("MEval", True)
  1818. Function MQuote(objArgs, objEnv)
  1819.         CheckArgNum objArgs, 1
  1820.         Set MQuote = objArgs.Item(1)
  1821. End Function
  1822. objNS.Add NewMalSym("quote"), NewVbsProc("MQuote", True)
  1823. Function MQuasiQuote(objArgs, objEnv)
  1824.         Dim varRes
  1825.         CheckArgNum objArgs, 1
  1826.         
  1827.         Set varRes = EvalLater( _
  1828.                 MQuasiQuoteExpand(objArgs, objEnv), objEnv)
  1829.         Set MQuasiQuote = varRes
  1830. End Function
  1831. objNS.Add NewMalSym("quasiquote"), NewVbsProc("MQuasiQuote", True)
  1832. Function MQuasiQuoteExpand(objArgs, objEnv)
  1833.         Dim varRes
  1834.         CheckArgNum objArgs, 1
  1835.         Set varRes = ExpandHelper(objArgs.Item(1))
  1836.         If varRes.Splice Then
  1837.                 Err.Raise vbObjectError, _
  1838.                         "MQuasiQuoteExpand", "Wrong return value type."
  1839.         End If
  1840.         Set varRes = varRes.Value
  1841.         Set MQuasiQuoteExpand = varRes
  1842. End Function
  1843. objNS.Add NewMalSym("quasiquoteexpand"), NewVbsProc("MQuasiQuoteExpand", True)
  1844. Class ExpandType
  1845.         Public Splice
  1846.         Public Value
  1847. End Class
  1848. Function NewExpandType(objValue, boolSplice)
  1849.         Dim varRes
  1850.         Set varRes = New ExpandType
  1851.         Set varRes.Value = objValue
  1852.         varRes.Splice = boolSplice
  1853.         Set NewExpandType = varRes
  1854. End Function
  1855. Function ExpandHelper(objArg)
  1856.         Dim varRes, boolSplice
  1857.         Dim varBuilder, varEType, i
  1858.         boolSplice = False
  1859.         Select Case objArg.Type
  1860.                 Case TYPES.LIST
  1861.                         Dim boolNormal
  1862.                         boolNormal = False
  1863.                         ' Check for unquotes.
  1864.                         Select Case objArg.Count
  1865.                                 Case 2
  1866.                                         ' Maybe have a bug here
  1867.                                         ' like (unquote a b c) should be throw a error
  1868.                                         If objArg.Item(0).Type = TYPES.SYMBOL Then
  1869.                                                 Select Case objArg.Item(0).Value
  1870.                                                         Case "unquote"
  1871.                                                                 Set varRes = objArg.Item(1)
  1872.                                                         Case "splice-unquote"
  1873.                                                                 Set varRes = objArg.Item(1)
  1874.                                                                 boolSplice = True
  1875.                                                         Case Else
  1876.                                                                 boolNormal = True
  1877.                                                 End Select
  1878.                                         Else
  1879.                                                 boolNormal = True
  1880.                                         End If
  1881.                                 Case Else
  1882.                                         boolNormal = True
  1883.                         End Select
  1884.                         
  1885.                         If boolNormal Then
  1886.                                 Set varRes = NewMalList(Array())
  1887.                                 Set varBuilder = varRes
  1888.                                 For i = 0 To objArg.Count - 1
  1889.                                         Set varEType = ExpandHelper(objArg.Item(i))
  1890.                                         If varEType.Splice Then
  1891.                                                 varBuilder.Add NewMalSym("concat")
  1892.                                         Else
  1893.                                                 varBuilder.Add NewMalSym("cons")
  1894.                                         End If
  1895.                                         varBuilder.Add varEType.Value
  1896.                                         varBuilder.Add NewMalList(Array())
  1897.                                         Set varBuilder = varBuilder.Item(2)
  1898.                                 Next
  1899.                         End If
  1900.                 Case TYPES.VECTOR
  1901.                         Set varRes = NewMalList(Array( _
  1902.                                 NewMalSym("vec"), NewMalList(Array())))
  1903.                         
  1904.                         Set varBuilder = varRes.Item(1)
  1905.                         For i = 0 To objArg.Count - 1
  1906.                                 Set varEType = ExpandHelper(objArg.Item(i))
  1907.                                 If varEType.Splice Then
  1908.                                         varBuilder.Add NewMalSym("concat")
  1909.                                 Else
  1910.                                         varBuilder.Add NewMalSym("cons")
  1911.                                 End If
  1912.                                 varBuilder.Add varEType.Value
  1913.                                 varBuilder.Add NewMalList(Array())
  1914.                                 Set varBuilder = varBuilder.Item(2)
  1915.                         Next
  1916.                 Case TYPES.HASHMAP
  1917.                         ' Maybe have a bug here.
  1918.                         ' e.g. {"key" ~value}
  1919.                         Set varRes = NewMalList(Array( _
  1920.                                 NewMalSym("quote"), objArg))
  1921.                 Case TYPES.SYMBOL
  1922.                         Set varRes = NewMalList(Array( _
  1923.                                 NewMalSym("quote"), objArg))
  1924.                 Case Else
  1925.                         ' Maybe have a bug here.
  1926.                         ' All unspecified type will return itself.
  1927.                         Set varRes = objArg
  1928.         End Select
  1929.         Set ExpandHelper = NewExpandType(varRes, boolSplice)
  1930. End Function
  1931. Function MDefMacro(objArgs, objEnv)
  1932.         Dim varRet
  1933.         CheckArgNum objArgs, 2
  1934.         CheckType objArgs.Item(1), TYPES.SYMBOL
  1935.         Set varRet = Evaluate(objArgs.Item(2), objEnv).Copy()
  1936.         CheckType varRet, TYPES.PROCEDURE
  1937.         varRet.IsMacro = True
  1938.         objEnv.Add objArgs.Item(1), varRet
  1939.         Set MDefMacro = varRet
  1940. End Function
  1941. objNS.Add NewMalSym("defmacro!"), NewVbsProc("MDefMacro", True)
  1942. Function IsMacroCall(objCode, objEnv)
  1943.         Dim varRes
  1944.         varRes = False
  1945.         ' VBS has no short-circuit evaluation.
  1946.         If objCode.Type = TYPES.LIST Then
  1947.                 If objCode.Count > 0 Then
  1948.                         If objCode.Item(0).Type = TYPES.SYMBOL Then
  1949.                                 Dim varValue
  1950.                                 Set varValue = objEnv.Get(objCode.Item(0))
  1951.                                 If varValue.Type = TYPES.PROCEDURE Then
  1952.                                         If varValue.IsMacro Then
  1953.                                                 varRes = True
  1954.                                         End If
  1955.                                 End If
  1956.                         End If
  1957.                 End If
  1958.         End If
  1959.         IsMacroCall = varRes
  1960. End Function
  1961. Function MacroExpand(ByVal objAST, ByVal objEnv)
  1962.         Dim varRes
  1963.         While IsMacroCall(objAST, objEnv)
  1964.                 Dim varMacro
  1965.                 Set varMacro = objEnv.Get(objAST.Item(0))
  1966.                 Set objAST = varMacro.MacroApply(objAST, objEnv)               
  1967.         Wend
  1968.         Set varRes = objAST
  1969.         Set MacroExpand = varRes
  1970. End Function
  1971. Function MMacroExpand(objArgs, objEnv)
  1972.         Dim varRes
  1973.         CheckArgNum objArgs, 1
  1974.         Set varRes = MacroExpand(objArgs.Item(1), objEnv)
  1975.         Set MMacroExpand = varRes
  1976. End Function
  1977. objNS.Add NewMalSym("macroexpand"), NewVbsProc("MMacroExpand", True)
  1978. Function MTry(objArgs, objEnv)
  1979.         Dim varRes
  1980.         
  1981.         If objArgs.Count - 1 < 1 Then
  1982.                 Err.Raise vbObjectError, _
  1983.                         "MTry", "Need more arguments."
  1984.         End If
  1985.         If objArgs.Count - 1 = 1 Then
  1986.                 Set varRes = EvalLater(objArgs.Item(1), objEnv)
  1987.                 Set MTry = varRes
  1988.                 Exit Function
  1989.         End If
  1990.         CheckArgNum objArgs, 2
  1991.         CheckType objArgs.Item(2), TYPES.LIST
  1992.         Dim objTry, objCatch
  1993.         Set objTry = objArgs.Item(1)
  1994.         Set objCatch = objArgs.Item(2)
  1995.         
  1996.         CheckArgNum objCatch, 2
  1997.         CheckType objCatch.Item(0), TYPES.SYMBOL
  1998.         CheckType objCatch.Item(1), TYPES.SYMBOL
  1999.         If objCatch.Item(0).Value <> "catch*" Then
  2000.                 Err.Raise vbObjectError, _
  2001.                         "MTry", "Unexpect argument(s)."
  2002.         End If
  2003.         
  2004.         On Error Resume Next
  2005.         Set varRes = Evaluate(objTry, objEnv)
  2006.         If Err.Number <> 0 Then
  2007.                 Dim objException
  2008.                 If Err.Source <> "MThrow" Then
  2009.                         Set objException = NewMalStr(Err.Description)
  2010.                 Else
  2011.                         Set objException = objExceptions.Item(Err.Description)
  2012.                         objExceptions.Remove Err.Description
  2013.                 End If
  2014.                
  2015.                 Call Err.Clear()
  2016.                 On Error Goto 0
  2017.                 ' The code below may cause error too.
  2018.                 ' So we should clear err info & throw out any errors.
  2019.                 ' Use 'quote' to avoid eval objExp again.
  2020.                 Set varRes = Evaluate(NewMalList(Array( _
  2021.                         NewMalSym("let*"), NewMalList(Array( _
  2022.                                 objCatch.Item(1), NewMalList(Array( _
  2023.                                                 NewMalSym("quote"), objException)))), _
  2024.                         objCatch.Item(2))), objEnv)
  2025.         Else
  2026.                 On Error Goto 0
  2027.         End If
  2028.         Set MTry = varRes
  2029. End Function
  2030. objNS.Add NewMalSym("try*"), NewVbsProc("MTry", True)
  2031. Call InitBuiltIn()
  2032. Call InitMacro()
  2033. Call InitArgs()
  2034. Sub InitArgs()
  2035.         Dim objArgs
  2036.         Set objArgs = NewMalList(Array())
  2037.         Dim i
  2038.         For i = 1 To WScript.Arguments.Count - 1
  2039.                 objArgs.Add NewMalStr(WScript.Arguments.Item(i))
  2040.         Next
  2041.         
  2042.         objNS.Add NewMalSym("*ARGV*"), objArgs
  2043.         
  2044.         If WScript.Arguments.Count > 0 Then
  2045.                 REP "(load-file """ + WScript.Arguments.Item(0) + """)"
  2046.                 WScript.Quit 0
  2047.         End If
  2048. End Sub
  2049. Randomize 1228
  2050. Call REPL()
  2051. Sub REPL()
  2052.         Dim strCode, strResult
  2053.         REP "(println (str ""Mal [""*host-language*""]""))"
  2054.         While True
  2055.                 WScript.StdOut.Write "user> "
  2056.                 On Error Resume Next
  2057.                         strCode = WScript.StdIn.ReadLine()
  2058.                         If Err.Number <> 0 Then WScript.Quit 0
  2059.                 On Error Goto 0
  2060.                
  2061.                 Dim strRes
  2062.                 On Error Resume Next
  2063.                         strRes = REP(strCode)
  2064.                         If Err.Number <> 0 Then
  2065.                                 If Err.Source = "MThrow" Then
  2066.                                         'WScript.StdErr.WriteLine Err.Source + ": " + _
  2067.                                         WScript.StdErr.WriteLine "Exception: " + _
  2068.                                                 PrintMalType(objExceptions.Item(Err.Description), True)
  2069.                                         objExceptions.Remove Err.Description
  2070.                                 Else
  2071.                                         'WScript.StdErr.WriteLine Err.Source + ": " + Err.Description
  2072.                                         WScript.StdErr.WriteLine "Exception: " + Err.Description
  2073.                                 End If
  2074.                         Else
  2075.                                 If strRes <> "" Then
  2076.                                         WScript.Echo strRes
  2077.                                 End If
  2078.                         End If
  2079.                 On Error Goto 0
  2080.         Wend
  2081. End Sub
  2082. Function Read(strCode)
  2083.         Set Read = ReadString(strCode)
  2084. End Function
  2085. Function Evaluate(ByVal objCode, ByVal objEnv)
  2086.         While True
  2087.                 If TypeName(objCode) = "Nothing" Then
  2088.                         Set Evaluate = Nothing
  2089.                         Exit Function
  2090.                 End If
  2091.                
  2092.                 Set objCode = MacroExpand(objCode, objEnv)
  2093.                 Dim varRet, objFirst
  2094.                 If objCode.Type = TYPES.LIST Then
  2095.                         If objCode.Count = 0 Then ' ()
  2096.                                 Set Evaluate = objCode
  2097.                                 Exit Function
  2098.                         End If
  2099.                         Set objFirst = Evaluate(objCode.Item(0), objEnv)
  2100.                         Set varRet = objFirst.Apply(objCode, objEnv)
  2101.                 Else
  2102.                         Set varRet = EvaluateAST(objCode, objEnv)
  2103.                 End If
  2104.                
  2105.                 If TypeName(varRet) = "TailCall" Then
  2106.                         ' NOTICE: If not specify 'ByVal',
  2107.                         ' Change of arguments will influence
  2108.                         ' the caller's variable!
  2109.                         Set objCode = varRet.objMalType
  2110.                         Set objEnv = varRet.objEnv
  2111.                 Else
  2112.                         Set Evaluate = varRet
  2113.                         Exit Function
  2114.                 End If
  2115.         Wend
  2116. End Function
  2117. Function EvaluateAST(objCode, objEnv)
  2118.         Dim varRet, i
  2119.         Select Case objCode.Type
  2120.                 Case TYPES.SYMBOL
  2121.                         Set varRet = objEnv.Get(objCode)
  2122.                 Case TYPES.LIST
  2123.                         Err.Raise vbObjectError, _
  2124.                                 "EvaluateAST", "Unexpect type."
  2125.                 Case TYPES.VECTOR
  2126.                         Set varRet = NewMalVec(Array())
  2127.                         For i = 0 To objCode.Count() - 1
  2128.                                 varRet.Add Evaluate(objCode.Item(i), objEnv)
  2129.                         Next
  2130.                 Case TYPES.HASHMAP
  2131.                         Set varRet = NewMalMap(Array(), Array())
  2132.                         For Each i In objCode.Keys()
  2133.                                 varRet.Add i, Evaluate(objCode.Item(i), objEnv)
  2134.                         Next
  2135.                 Case Else
  2136.                         Set varRet = objCode
  2137.         End Select
  2138.         Set EvaluateAST = varRet
  2139. End Function
  2140. Function EvaluateRest(objCode, objEnv)
  2141.         Dim varRet, i
  2142.         Select Case objCode.Type
  2143.                 Case TYPES.LIST
  2144.                         Set varRet = NewMalList(Array(NewMalNil()))
  2145.                         For i = 1 To objCode.Count() - 1
  2146.                                 varRet.Add Evaluate(objCode.Item(i), objEnv)
  2147.                         Next
  2148.                 Case Else
  2149.                         Err.Raise vbObjectError, _
  2150.                                 "EvaluateRest", "Unexpected type."
  2151.         End Select
  2152.         Set EvaluateRest = varRet
  2153. End Function
  2154. Function Print(objCode)
  2155.         Print = PrintMalType(objCode, True)
  2156. End Function
  2157. Function REP(strCode)
  2158.         REP = Print(Evaluate(Read(strCode), objNS))
  2159. End Function
  2160. Sub Include(strFileName)
  2161.         With CreateObject("Scripting.FileSystemObject")
  2162.                 ExecuteGlobal .OpenTextFile( _
  2163.                         .GetParentFolderName( _
  2164.                         .GetFile(WScript.ScriptFullName)) & _
  2165.                         "\" & strFileName).ReadAll
  2166.         End With
  2167. End Sub
复制代码
3

评分人数

不明觉厉                                           .

QQ 20147578

TOP

几个测试用例(相等于语法教程了)
  1. ;; Testing evaluation of arithmetic operations
  2. (+ 1 2)
  3. ;=>3
  4. (+ 5 (* 2 3))
  5. ;=>11
  6. (- (+ 5 (* 2 3)) 3)
  7. ;=>8
  8. (/ (- (+ 5 (* 2 3)) 3) 4)
  9. ;=>2
  10. (/ (- (+ 515 (* 87 311)) 302) 27)
  11. ;=>1010
  12. (* -3 6)
  13. ;=>-18
  14. (/ (- (+ 515 (* -87 311)) 296) 27)
  15. ;=>-994
  16. ;;; This should throw an error with no return value
  17. (abc 1 2 3)
  18. ;/.+
  19. ;; Testing empty list
  20. ()
  21. ;=>()
  22. ;>>> deferrable=True
  23. ;;
  24. ;; -------- Deferrable Functionality --------
  25. ;; Testing evaluation within collection literals
  26. [1 2 (+ 1 2)]
  27. ;=>[1 2 3]
  28. {"a" (+ 7 8)}
  29. ;=>{"a" 15}
  30. {:a (+ 7 8)}
  31. ;=>{:a 15}
  32. ;; Check that evaluation hasn't broken empty collections
  33. []
  34. ;=>[]
  35. {}
  36. ;=>{}
复制代码
  1. ;; Testing REPL_ENV
  2. (+ 1 2)
  3. ;=>3
  4. (/ (- (+ 5 (* 2 3)) 3) 4)
  5. ;=>2
  6. ;; Testing def!
  7. (def! x 3)
  8. ;=>3
  9. x
  10. ;=>3
  11. (def! x 4)
  12. ;=>4
  13. x
  14. ;=>4
  15. (def! y (+ 1 7))
  16. ;=>8
  17. y
  18. ;=>8
  19. ;; Verifying symbols are case-sensitive
  20. (def! mynum 111)
  21. ;=>111
  22. (def! MYNUM 222)
  23. ;=>222
  24. mynum
  25. ;=>111
  26. MYNUM
  27. ;=>222
  28. ;; Check env lookup non-fatal error
  29. (abc 1 2 3)
  30. ;/.*\'?abc\'? not found.*
  31. ;; Check that error aborts def!
  32. (def! w 123)
  33. (def! w (abc))
  34. w
  35. ;=>123
  36. ;; Testing let*
  37. (let* (z 9) z)
  38. ;=>9
  39. (let* (x 9) x)
  40. ;=>9
  41. x
  42. ;=>4
  43. (let* (z (+ 2 3)) (+ 1 z))
  44. ;=>6
  45. (let* (p (+ 2 3) q (+ 2 p)) (+ p q))
  46. ;=>12
  47. (def! y (let* (z 7) z))
  48. y
  49. ;=>7
  50. ;; Testing outer environment
  51. (def! a 4)
  52. ;=>4
  53. (let* (q 9) q)
  54. ;=>9
  55. (let* (q 9) a)
  56. ;=>4
  57. (let* (z 2) (let* (q 9) a))
  58. ;=>4
  59. ;>>> deferrable=True
  60. ;;
  61. ;; -------- Deferrable Functionality --------
  62. ;; Testing let* with vector bindings
  63. (let* [z 9] z)
  64. ;=>9
  65. (let* [p (+ 2 3) q (+ 2 p)] (+ p q))
  66. ;=>12
  67. ;; Testing vector evaluation
  68. (let* (a 5 b 6) [3 4 a [b 7] 8])
  69. ;=>[3 4 5 [6 7] 8]
  70. ;>>> soft=True
  71. ;>>> optional=True
  72. ;;
  73. ;; -------- Optional Functionality --------
  74. ;; Check that last assignment takes priority
  75. (let* (x 2 x 3) x)
  76. ;=>3
复制代码
  1. ;; -----------------------------------------------------
  2. ;; Testing list functions
  3. (list)
  4. ;=>()
  5. (list? (list))
  6. ;=>true
  7. (empty? (list))
  8. ;=>true
  9. (empty? (list 1))
  10. ;=>false
  11. (list 1 2 3)
  12. ;=>(1 2 3)
  13. (count (list 1 2 3))
  14. ;=>3
  15. (count (list))
  16. ;=>0
  17. (count nil)
  18. ;=>0
  19. (if (> (count (list 1 2 3)) 3) 89 78)
  20. ;=>78
  21. (if (>= (count (list 1 2 3)) 3) 89 78)
  22. ;=>89
  23. ;; Testing if form
  24. (if true 7 8)
  25. ;=>7
  26. (if false 7 8)
  27. ;=>8
  28. (if false 7 false)
  29. ;=>false
  30. (if true (+ 1 7) (+ 1 8))
  31. ;=>8
  32. (if false (+ 1 7) (+ 1 8))
  33. ;=>9
  34. (if nil 7 8)
  35. ;=>8
  36. (if 0 7 8)
  37. ;=>7
  38. (if (list) 7 8)
  39. ;=>7
  40. (if (list 1 2 3) 7 8)
  41. ;=>7
  42. (= (list) nil)
  43. ;=>false
  44. ;; Testing 1-way if form
  45. (if false (+ 1 7))
  46. ;=>nil
  47. (if nil 8)
  48. ;=>nil
  49. (if nil 8 7)
  50. ;=>7
  51. (if true (+ 1 7))
  52. ;=>8
  53. ;; Testing basic conditionals
  54. (= 2 1)
  55. ;=>false
  56. (= 1 1)
  57. ;=>true
  58. (= 1 2)
  59. ;=>false
  60. (= 1 (+ 1 1))
  61. ;=>false
  62. (= 2 (+ 1 1))
  63. ;=>true
  64. (= nil 1)
  65. ;=>false
  66. (= nil nil)
  67. ;=>true
  68. (> 2 1)
  69. ;=>true
  70. (> 1 1)
  71. ;=>false
  72. (> 1 2)
  73. ;=>false
  74. (>= 2 1)
  75. ;=>true
  76. (>= 1 1)
  77. ;=>true
  78. (>= 1 2)
  79. ;=>false
  80. (< 2 1)
  81. ;=>false
  82. (< 1 1)
  83. ;=>false
  84. (< 1 2)
  85. ;=>true
  86. (<= 2 1)
  87. ;=>false
  88. (<= 1 1)
  89. ;=>true
  90. (<= 1 2)
  91. ;=>true
  92. ;; Testing equality
  93. (= 1 1)
  94. ;=>true
  95. (= 0 0)
  96. ;=>true
  97. (= 1 0)
  98. ;=>false
  99. (= true true)
  100. ;=>true
  101. (= false false)
  102. ;=>true
  103. (= nil nil)
  104. ;=>true
  105. (= (list) (list))
  106. ;=>true
  107. (= (list) ())
  108. ;=>true
  109. (= (list 1 2) (list 1 2))
  110. ;=>true
  111. (= (list 1) (list))
  112. ;=>false
  113. (= (list) (list 1))
  114. ;=>false
  115. (= 0 (list))
  116. ;=>false
  117. (= (list) 0)
  118. ;=>false
  119. (= (list nil) (list))
  120. ;=>false
  121. ;; Testing builtin and user defined functions
  122. (+ 1 2)
  123. ;=>3
  124. ( (fn* (a b) (+ b a)) 3 4)
  125. ;=>7
  126. ( (fn* () 4) )
  127. ;=>4
  128. ( (fn* (f x) (f x)) (fn* (a) (+ 1 a)) 7)
  129. ;=>8
  130. ;; Testing closures
  131. ( ( (fn* (a) (fn* (b) (+ a b))) 5) 7)
  132. ;=>12
  133. (def! gen-plus5 (fn* () (fn* (b) (+ 5 b))))
  134. (def! plus5 (gen-plus5))
  135. (plus5 7)
  136. ;=>12
  137. (def! gen-plusX (fn* (x) (fn* (b) (+ x b))))
  138. (def! plus7 (gen-plusX 7))
  139. (plus7 8)
  140. ;=>15
  141. ;; Testing do form
  142. (do (prn 101))
  143. ;/101
  144. ;=>nil
  145. (do (prn 102) 7)
  146. ;/102
  147. ;=>7
  148. (do (prn 101) (prn 102) (+ 1 2))
  149. ;/101
  150. ;/102
  151. ;=>3
  152. (do (def! a 6) 7 (+ a 8))
  153. ;=>14
  154. a
  155. ;=>6
  156. ;; Testing special form case-sensitivity
  157. (def! DO (fn* (a) 7))
  158. (DO 3)
  159. ;=>7
  160. ;; Testing recursive sumdown function
  161. (def! sumdown (fn* (N) (if (> N 0) (+ N (sumdown  (- N 1))) 0)))
  162. (sumdown 1)
  163. ;=>1
  164. (sumdown 2)
  165. ;=>3
  166. (sumdown 6)
  167. ;=>21
  168. ;; Testing recursive fibonacci function
  169. (def! fib (fn* (N) (if (= N 0) 1 (if (= N 1) 1 (+ (fib (- N 1)) (fib (- N 2)))))))
  170. (fib 1)
  171. ;=>1
  172. (fib 2)
  173. ;=>2
  174. (fib 4)
  175. ;=>5
  176. ;; Testing recursive function in environment.
  177. (let* (f (fn* () x) x 3) (f))
  178. ;=>3
  179. (let* (cst (fn* (n) (if (= n 0) nil (cst (- n 1))))) (cst 1))
  180. ;=>nil
  181. (let* (f (fn* (n) (if (= n 0) 0 (g (- n 1)))) g (fn* (n) (f n))) (f 2))
  182. ;=>0
  183. ;>>> deferrable=True
  184. ;;
  185. ;; -------- Deferrable Functionality --------
  186. ;; Testing if on strings
  187. (if "" 7 8)
  188. ;=>7
  189. ;; Testing string equality
  190. (= "" "")
  191. ;=>true
  192. (= "abc" "abc")
  193. ;=>true
  194. (= "abc" "")
  195. ;=>false
  196. (= "" "abc")
  197. ;=>false
  198. (= "abc" "def")
  199. ;=>false
  200. (= "abc" "ABC")
  201. ;=>false
  202. (= (list) "")
  203. ;=>false
  204. (= "" (list))
  205. ;=>false
  206. ;; Testing variable length arguments
  207. ( (fn* (& more) (count more)) 1 2 3)
  208. ;=>3
  209. ( (fn* (& more) (list? more)) 1 2 3)
  210. ;=>true
  211. ( (fn* (& more) (count more)) 1)
  212. ;=>1
  213. ( (fn* (& more) (count more)) )
  214. ;=>0
  215. ( (fn* (& more) (list? more)) )
  216. ;=>true
  217. ( (fn* (a & more) (count more)) 1 2 3)
  218. ;=>2
  219. ( (fn* (a & more) (count more)) 1)
  220. ;=>0
  221. ( (fn* (a & more) (list? more)) 1)
  222. ;=>true
  223. ;; Testing language defined not function
  224. (not false)
  225. ;=>true
  226. (not nil)
  227. ;=>true
  228. (not true)
  229. ;=>false
  230. (not "a")
  231. ;=>false
  232. (not 0)
  233. ;=>false
  234. ;; -----------------------------------------------------
  235. ;; Testing string quoting
  236. ""
  237. ;=>""
  238. "abc"
  239. ;=>"abc"
  240. "abc  def"
  241. ;=>"abc  def"
  242. "\""
  243. ;=>"\""
  244. "abc\ndef\nghi"
  245. ;=>"abc\ndef\nghi"
  246. "abc\\def\\ghi"
  247. ;=>"abc\\def\\ghi"
  248. "\\n"
  249. ;=>"\\n"
  250. ;; Testing pr-str
  251. (pr-str)
  252. ;=>""
  253. (pr-str "")
  254. ;=>"\"\""
  255. (pr-str "abc")
  256. ;=>"\"abc\""
  257. (pr-str "abc  def" "ghi jkl")
  258. ;=>"\"abc  def\" \"ghi jkl\""
  259. (pr-str "\"")
  260. ;=>"\"\\\"\""
  261. (pr-str (list 1 2 "abc" "\"") "def")
  262. ;=>"(1 2 \"abc\" \"\\\"\") \"def\""
  263. (pr-str "abc\ndef\nghi")
  264. ;=>"\"abc\\ndef\\nghi\""
  265. (pr-str "abc\\def\\ghi")
  266. ;=>"\"abc\\\\def\\\\ghi\""
  267. (pr-str (list))
  268. ;=>"()"
  269. ;; Testing str
  270. (str)
  271. ;=>""
  272. (str "")
  273. ;=>""
  274. (str "abc")
  275. ;=>"abc"
  276. (str "\"")
  277. ;=>"\""
  278. (str 1 "abc" 3)
  279. ;=>"1abc3"
  280. (str "abc  def" "ghi jkl")
  281. ;=>"abc  defghi jkl"
  282. (str "abc\ndef\nghi")
  283. ;=>"abc\ndef\nghi"
  284. (str "abc\\def\\ghi")
  285. ;=>"abc\\def\\ghi"
  286. (str (list 1 2 "abc" "\"") "def")
  287. ;=>"(1 2 abc \")def"
  288. (str (list))
  289. ;=>"()"
  290. ;; Testing prn
  291. (prn)
  292. ;/
  293. ;=>nil
  294. (prn "")
  295. ;/""
  296. ;=>nil
  297. (prn "abc")
  298. ;/"abc"
  299. ;=>nil
  300. (prn "abc  def" "ghi jkl")
  301. ;/"abc  def" "ghi jkl"
  302. (prn "\"")
  303. ;/"\\""
  304. ;=>nil
  305. (prn "abc\ndef\nghi")
  306. ;/"abc\\ndef\\nghi"
  307. ;=>nil
  308. (prn "abc\\def\\ghi")
  309. ;/"abc\\\\def\\\\ghi"
  310. nil
  311. (prn (list 1 2 "abc" "\"") "def")
  312. ;/\(1 2 "abc" "\\""\) "def"
  313. ;=>nil
  314. ;; Testing println
  315. (println)
  316. ;/
  317. ;=>nil
  318. (println "")
  319. ;/
  320. ;=>nil
  321. (println "abc")
  322. ;/abc
  323. ;=>nil
  324. (println "abc  def" "ghi jkl")
  325. ;/abc  def ghi jkl
  326. (println "\"")
  327. ;/"
  328. ;=>nil
  329. (println "abc\ndef\nghi")
  330. ;/abc
  331. ;/def
  332. ;/ghi
  333. ;=>nil
  334. (println "abc\\def\\ghi")
  335. ;/abc\\def\\ghi
  336. ;=>nil
  337. (println (list 1 2 "abc" "\"") "def")
  338. ;/\(1 2 abc "\) def
  339. ;=>nil
  340. ;; Testing keywords
  341. (= :abc :abc)
  342. ;=>true
  343. (= :abc :def)
  344. ;=>false
  345. (= :abc ":abc")
  346. ;=>false
  347. (= (list :abc) (list :abc))
  348. ;=>true
  349. ;; Testing vector truthiness
  350. (if [] 7 8)
  351. ;=>7
  352. ;; Testing vector printing
  353. (pr-str [1 2 "abc" "\""] "def")
  354. ;=>"[1 2 \"abc\" \"\\\"\"] \"def\""
  355. (pr-str [])
  356. ;=>"[]"
  357. (str [1 2 "abc" "\""] "def")
  358. ;=>"[1 2 abc \"]def"
  359. (str [])
  360. ;=>"[]"
  361. ;; Testing vector functions
  362. (count [1 2 3])
  363. ;=>3
  364. (empty? [1 2 3])
  365. ;=>false
  366. (empty? [])
  367. ;=>true
  368. (list? [4 5 6])
  369. ;=>false
  370. ;; Testing vector equality
  371. (= [] (list))
  372. ;=>true
  373. (= [7 8] [7 8])
  374. ;=>true
  375. (= [:abc] [:abc])
  376. ;=>true
  377. (= (list 1 2) [1 2])
  378. ;=>true
  379. (= (list 1) [])
  380. ;=>false
  381. (= [] [1])
  382. ;=>false
  383. (= 0 [])
  384. ;=>false
  385. (= [] 0)
  386. ;=>false
  387. (= [] "")
  388. ;=>false
  389. (= "" [])
  390. ;=>false
  391. ;; Testing vector parameter lists
  392. ( (fn* [] 4) )
  393. ;=>4
  394. ( (fn* [f x] (f x)) (fn* [a] (+ 1 a)) 7)
  395. ;=>8
  396. ;; Nested vector/list equality
  397. (= [(list)] (list []))
  398. ;=>true
  399. (= [1 2 (list 3 4 [5 6])] (list 1 2 [3 4 (list 5 6)]))
  400. ;=>true
复制代码
  1. ;; Testing cons function
  2. (cons 1 (list))
  3. ;=>(1)
  4. (cons 1 (list 2))
  5. ;=>(1 2)
  6. (cons 1 (list 2 3))
  7. ;=>(1 2 3)
  8. (cons (list 1) (list 2 3))
  9. ;=>((1) 2 3)
  10. (def! a (list 2 3))
  11. (cons 1 a)
  12. ;=>(1 2 3)
  13. a
  14. ;=>(2 3)
  15. ;; Testing concat function
  16. (concat)
  17. ;=>()
  18. (concat (list 1 2))
  19. ;=>(1 2)
  20. (concat (list 1 2) (list 3 4))
  21. ;=>(1 2 3 4)
  22. (concat (list 1 2) (list 3 4) (list 5 6))
  23. ;=>(1 2 3 4 5 6)
  24. (concat (concat))
  25. ;=>()
  26. (concat (list) (list))
  27. ;=>()
  28. (= () (concat))
  29. ;=>true
  30. (def! a (list 1 2))
  31. (def! b (list 3 4))
  32. (concat a b (list 5 6))
  33. ;=>(1 2 3 4 5 6)
  34. a
  35. ;=>(1 2)
  36. b
  37. ;=>(3 4)
  38. ;; Testing regular quote
  39. (quote 7)
  40. ;=>7
  41. (quote (1 2 3))
  42. ;=>(1 2 3)
  43. (quote (1 2 (3 4)))
  44. ;=>(1 2 (3 4))
  45. ;; Testing simple quasiquote
  46. (quasiquote nil)
  47. ;=>nil
  48. (quasiquote 7)
  49. ;=>7
  50. (quasiquote a)
  51. ;=>a
  52. (quasiquote {"a" b})
  53. ;=>{"a" b}
  54. ;; Testing quasiquote with lists
  55. (quasiquote ())
  56. ;=>()
  57. (quasiquote (1 2 3))
  58. ;=>(1 2 3)
  59. (quasiquote (a))
  60. ;=>(a)
  61. (quasiquote (1 2 (3 4)))
  62. ;=>(1 2 (3 4))
  63. (quasiquote (nil))
  64. ;=>(nil)
  65. (quasiquote (1 ()))
  66. ;=>(1 ())
  67. (quasiquote (() 1))
  68. ;=>(() 1)
  69. (quasiquote (1 () 2))
  70. ;=>(1 () 2)
  71. (quasiquote (()))
  72. ;=>(())
  73. ;; (quasiquote (f () g (h) i (j k) l))
  74. ;; =>(f () g (h) i (j k) l)
  75. ;; Testing unquote
  76. (quasiquote (unquote 7))
  77. ;=>7
  78. (def! a 8)
  79. ;=>8
  80. (quasiquote a)
  81. ;=>a
  82. (quasiquote (unquote a))
  83. ;=>8
  84. (quasiquote (1 a 3))
  85. ;=>(1 a 3)
  86. (quasiquote (1 (unquote a) 3))
  87. ;=>(1 8 3)
  88. (def! b (quote (1 "b" "d")))
  89. ;=>(1 "b" "d")
  90. (quasiquote (1 b 3))
  91. ;=>(1 b 3)
  92. (quasiquote (1 (unquote b) 3))
  93. ;=>(1 (1 "b" "d") 3)
  94. (quasiquote ((unquote 1) (unquote 2)))
  95. ;=>(1 2)
  96. ;; Quasiquote and environments
  97. (let* (x 0) (quasiquote (unquote x)))
  98. ;=>0
  99. ;; Testing splice-unquote
  100. (def! c (quote (1 "b" "d")))
  101. ;=>(1 "b" "d")
  102. (quasiquote (1 c 3))
  103. ;=>(1 c 3)
  104. (quasiquote (1 (splice-unquote c) 3))
  105. ;=>(1 1 "b" "d" 3)
  106. (quasiquote (1 (splice-unquote c)))
  107. ;=>(1 1 "b" "d")
  108. (quasiquote ((splice-unquote c) 2))
  109. ;=>(1 "b" "d" 2)
  110. (quasiquote ((splice-unquote c) (splice-unquote c)))
  111. ;=>(1 "b" "d" 1 "b" "d")
  112. ;; Testing symbol equality
  113. (= (quote abc) (quote abc))
  114. ;=>true
  115. (= (quote abc) (quote abcd))
  116. ;=>false
  117. (= (quote abc) "abc")
  118. ;=>false
  119. (= "abc" (quote abc))
  120. ;=>false
  121. (= "abc" (str (quote abc)))
  122. ;=>true
  123. (= (quote abc) nil)
  124. ;=>false
  125. (= nil (quote abc))
  126. ;=>false
  127. ;>>> deferrable=True
  128. ;;
  129. ;; -------- Deferrable Functionality --------
  130. ;; Testing ' (quote) reader macro
  131. '7
  132. ;=>7
  133. '(1 2 3)
  134. ;=>(1 2 3)
  135. '(1 2 (3 4))
  136. ;=>(1 2 (3 4))
  137. ;; Testing cons and concat with vectors
  138. (cons 1 [])
  139. ;=>(1)
  140. (cons [1] [2 3])
  141. ;=>([1] 2 3)
  142. (cons 1 [2 3])
  143. ;=>(1 2 3)
  144. (concat [1 2] (list 3 4) [5 6])
  145. ;=>(1 2 3 4 5 6)
  146. (concat [1 2])
  147. ;=>(1 2)
  148. ;>>> optional=True
  149. ;;
  150. ;; -------- Optional Functionality --------
  151. ;; Testing ` (quasiquote) reader macro
  152. `7
  153. ;=>7
  154. `(1 2 3)
  155. ;=>(1 2 3)
  156. `(1 2 (3 4))
  157. ;=>(1 2 (3 4))
  158. `(nil)
  159. ;=>(nil)
  160. ;; Testing ~ (unquote) reader macro
  161. `~7
  162. ;=>7
  163. (def! a 8)
  164. ;=>8
  165. `(1 ~a 3)
  166. ;=>(1 8 3)
  167. (def! b '(1 "b" "d"))
  168. ;=>(1 "b" "d")
  169. `(1 b 3)
  170. ;=>(1 b 3)
  171. `(1 ~b 3)
  172. ;=>(1 (1 "b" "d") 3)
  173. ;; Testing ~@ (splice-unquote) reader macro
  174. (def! c '(1 "b" "d"))
  175. ;=>(1 "b" "d")
  176. `(1 c 3)
  177. ;=>(1 c 3)
  178. `(1 ~@c 3)
  179. ;=>(1 1 "b" "d" 3)
  180. ;>>> soft=True
  181. ;; Testing vec function
  182. (vec (list))
  183. ;=>[]
  184. (vec (list 1))
  185. ;=>[1]
  186. (vec (list 1 2))
  187. ;=>[1 2]
  188. (vec [])
  189. ;=>[]
  190. (vec [1 2])
  191. ;=>[1 2]
  192. ;; Testing that vec does not mutate the original list
  193. (def! a (list 1 2))
  194. (vec a)
  195. ;=>[1 2]
  196. a
  197. ;=>(1 2)
  198. ;; Test quine
  199. ((fn* (q) (quasiquote ((unquote q) (quote (unquote q))))) (quote (fn* (q) (quasiquote ((unquote q) (quote (unquote q)))))))
  200. ;=>((fn* (q) (quasiquote ((unquote q) (quote (unquote q))))) (quote (fn* (q) (quasiquote ((unquote q) (quote (unquote q)))))))
  201. ;; Testing quasiquote with vectors
  202. (quasiquote [])
  203. ;=>[]
  204. (quasiquote [[]])
  205. ;=>[[]]
  206. (quasiquote [()])
  207. ;=>[()]
  208. (quasiquote ([]))
  209. ;=>([])
  210. (def! a 8)
  211. ;=>8
  212. `[1 a 3]
  213. ;=>[1 a 3]
  214. (quasiquote [a [] b [c] d [e f] g])
  215. ;=>[a [] b [c] d [e f] g]
  216. ;; Testing unquote with vectors
  217. `[~a]
  218. ;=>[8]
  219. `[(~a)]
  220. ;=>[(8)]
  221. `([~a])
  222. ;=>([8])
  223. `[a ~a a]
  224. ;=>[a 8 a]
  225. `([a ~a a])
  226. ;=>([a 8 a])
  227. `[(a ~a a)]
  228. ;=>[(a 8 a)]
  229. ;; Testing splice-unquote with vectors
  230. (def! c '(1 "b" "d"))
  231. ;=>(1 "b" "d")
  232. `[~@c]
  233. ;=>[1 "b" "d"]
  234. `[(~@c)]
  235. ;=>[(1 "b" "d")]
  236. `([~@c])
  237. ;=>([1 "b" "d"])
  238. `[1 ~@c 3]
  239. ;=>[1 1 "b" "d" 3]
  240. `([1 ~@c 3])
  241. ;=>([1 1 "b" "d" 3])
  242. `[(1 ~@c 3)]
  243. ;=>[(1 1 "b" "d" 3)]
  244. ;; Misplaced unquote or splice-unquote
  245. `(0 unquote)
  246. ;=>(0 unquote)
  247. `(0 splice-unquote)
  248. ;=>(0 splice-unquote)
  249. `[unquote 0]
  250. ;=>[unquote 0]
  251. `[splice-unquote 0]
  252. ;=>[splice-unquote 0]
  253. ;; Debugging quasiquote
  254. (quasiquoteexpand nil)
  255. ;=>nil
  256. (quasiquoteexpand 7)
  257. ;=>7
  258. (quasiquoteexpand a)
  259. ;=>(quote a)
  260. (quasiquoteexpand {"a" b})
  261. ;=>(quote {"a" b})
  262. (quasiquoteexpand ())
  263. ;=>()
  264. (quasiquoteexpand (1 2 3))
  265. ;=>(cons 1 (cons 2 (cons 3 ())))
  266. (quasiquoteexpand (a))
  267. ;=>(cons (quote a) ())
  268. (quasiquoteexpand (1 2 (3 4)))
  269. ;=>(cons 1 (cons 2 (cons (cons 3 (cons 4 ())) ())))
  270. (quasiquoteexpand (nil))
  271. ;=>(cons nil ())
  272. (quasiquoteexpand (1 ()))
  273. ;=>(cons 1 (cons () ()))
  274. (quasiquoteexpand (() 1))
  275. ;=>(cons () (cons 1 ()))
  276. (quasiquoteexpand (1 () 2))
  277. ;=>(cons 1 (cons () (cons 2 ())))
  278. (quasiquoteexpand (()))
  279. ;=>(cons () ())
  280. (quasiquoteexpand (f () g (h) i (j k) l))
  281. ;=>(cons (quote f) (cons () (cons (quote g) (cons (cons (quote h) ()) (cons (quote i) (cons (cons (quote j) (cons (quote k) ())) (cons (quote l) ())))))))
  282. (quasiquoteexpand (unquote 7))
  283. ;=>7
  284. (quasiquoteexpand a)
  285. ;=>(quote a)
  286. (quasiquoteexpand (unquote a))
  287. ;=>a
  288. (quasiquoteexpand (1 a 3))
  289. ;=>(cons 1 (cons (quote a) (cons 3 ())))
  290. (quasiquoteexpand (1 (unquote a) 3))
  291. ;=>(cons 1 (cons a (cons 3 ())))
  292. (quasiquoteexpand (1 b 3))
  293. ;=>(cons 1 (cons (quote b) (cons 3 ())))
  294. (quasiquoteexpand (1 (unquote b) 3))
  295. ;=>(cons 1 (cons b (cons 3 ())))
  296. (quasiquoteexpand ((unquote 1) (unquote 2)))
  297. ;=>(cons 1 (cons 2 ()))
  298. (quasiquoteexpand (a (splice-unquote (b c)) d))
  299. ;=>(cons (quote a) (concat (b c) (cons (quote d) ())))
  300. (quasiquoteexpand (1 c 3))
  301. ;=>(cons 1 (cons (quote c) (cons 3 ())))
  302. (quasiquoteexpand (1 (splice-unquote c) 3))
  303. ;=>(cons 1 (concat c (cons 3 ())))
  304. (quasiquoteexpand (1 (splice-unquote c)))
  305. ;=>(cons 1 (concat c ()))
  306. (quasiquoteexpand ((splice-unquote c) 2))
  307. ;=>(concat c (cons 2 ()))
  308. (quasiquoteexpand ((splice-unquote c) (splice-unquote c)))
  309. ;=>(concat c (concat c ()))
  310. (quasiquoteexpand [])
  311. ;=>(vec ())
  312. (quasiquoteexpand [[]])
  313. ;=>(vec (cons (vec ()) ()))
  314. (quasiquoteexpand [()])
  315. ;=>(vec (cons () ()))
  316. (quasiquoteexpand ([]))
  317. ;=>(cons (vec ()) ())
  318. (quasiquoteexpand [1 a 3])
  319. ;=>(vec (cons 1 (cons (quote a) (cons 3 ()))))
  320. (quasiquoteexpand [a [] b [c] d [e f] g])
  321. ;=>(vec (cons (quote a) (cons (vec ()) (cons (quote b) (cons (vec (cons (quote c) ())) (cons (quote d) (cons (vec (cons (quote e) (cons (quote f) ()))) (cons (quote g) ()))))))))
复制代码
  1. ;;; TODO: really a step5 test
  2. ;;
  3. ;; Testing that (do (do)) not broken by TCO
  4. (do (do 1 2))
  5. ;=>2
  6. ;;
  7. ;; Testing read-string, eval and slurp
  8. (read-string "(1 2 (3 4) nil)")
  9. ;=>(1 2 (3 4) nil)
  10. (= nil (read-string "nil"))
  11. ;=>true
  12. (read-string "(+ 2 3)")
  13. ;=>(+ 2 3)
  14. (read-string "\"\n\"")
  15. ;=>"\n"
  16. (read-string "7 ;; comment")
  17. ;=>7
  18. ;;; Differing output, but make sure no fatal error
  19. (read-string ";; comment")
  20. (eval (read-string "(+ 2 3)"))
  21. ;=>5
  22. (slurp "../tests/test.txt")
  23. ;=>"A line of text\n"
  24. ;;; Load the same file twice.
  25. (slurp "../tests/test.txt")
  26. ;=>"A line of text\n"
  27. ;; Testing load-file
  28. (load-file "../tests/inc.mal")
  29. ;=>nil
  30. (inc1 7)
  31. ;=>8
  32. (inc2 7)
  33. ;=>9
  34. (inc3 9)
  35. ;=>12
  36. ;;
  37. ;; Testing atoms
  38. (def! inc3 (fn* (a) (+ 3 a)))
  39. (def! a (atom 2))
  40. ;=>(atom 2)
  41. (atom? a)
  42. ;=>true
  43. (atom? 1)
  44. ;=>false
  45. (deref a)
  46. ;=>2
  47. (reset! a 3)
  48. ;=>3
  49. (deref a)
  50. ;=>3
  51. (swap! a inc3)
  52. ;=>6
  53. (deref a)
  54. ;=>6
  55. (swap! a (fn* (a) a))
  56. ;=>6
  57. (swap! a (fn* (a) (* 2 a)))
  58. ;=>12
  59. (swap! a (fn* (a b) (* a b)) 10)
  60. ;=>120
  61. (swap! a + 3)
  62. ;=>123
  63. ;; Testing swap!/closure interaction
  64. (def! inc-it (fn* (a) (+ 1 a)))
  65. (def! atm (atom 7))
  66. (def! f (fn* () (swap! atm inc-it)))
  67. (f)
  68. ;=>8
  69. (f)
  70. ;=>9
  71. ;; Testing whether closures can retain atoms
  72. (def! g (let* (atm (atom 0)) (fn* () (deref atm))))
  73. (def! atm (atom 1))
  74. (g)
  75. ;=>0
  76. ;>>> deferrable=True
  77. ;;
  78. ;; -------- Deferrable Functionality --------
  79. ;; Testing reading of large files
  80. (load-file "../tests/computations.mal")
  81. ;=>nil
  82. (sumdown 2)
  83. ;=>3
  84. (fib 2)
  85. ;=>1
  86. ;; Testing `@` reader macro (short for `deref`)
  87. (def! atm (atom 9))
  88. @atm
  89. ;=>9
  90. ;;; TODO: really a step5 test
  91. ;; Testing that vector params not broken by TCO
  92. (def! g (fn* [] 78))
  93. (g)
  94. ;=>78
  95. (def! g (fn* [a] (+ a 78)))
  96. (g 3)
  97. ;=>81
  98. ;;
  99. ;; Testing that *ARGV* exists and is an empty list
  100. (list? *ARGV*)
  101. ;=>true
  102. *ARGV*
  103. ;=>()
  104. ;;
  105. ;; Testing that eval sets aa in root scope, and that it is found in nested scope
  106. (let* (b 12) (do (eval (read-string "(def! aa 7)")) aa ))
  107. ;=>7
  108. ;>>> soft=True
  109. ;>>> optional=True
  110. ;;
  111. ;; -------- Optional Functionality --------
  112. ;; Testing comments in a file
  113. (load-file "../tests/incB.mal")
  114. ;=>nil
  115. (inc4 7)
  116. ;=>11
  117. (inc5 7)
  118. ;=>12
  119. ;; Testing map literal across multiple lines in a file
  120. (load-file "../tests/incC.mal")
  121. ;=>nil
  122. mymap
  123. ;=>{"a" 1}
  124. ;; Checking that eval does not use local environments.
  125. (def! a 1)
  126. ;=>1
  127. (let* (a 2) (eval (read-string "a")))
  128. ;=>1
  129. ;; Non alphanumeric characters in comments in read-string
  130. (read-string "1;!")
  131. ;=>1
  132. (read-string "1;\"")
  133. ;=>1
  134. (read-string "1;#")
  135. ;=>1
  136. (read-string "1;$")
  137. ;=>1
  138. (read-string "1;%")
  139. ;=>1
  140. (read-string "1;'")
  141. ;=>1
  142. (read-string "1;\\")
  143. ;=>1
  144. (read-string "1;\\\\")
  145. ;=>1
  146. (read-string "1;\\\\\\")
  147. ;=>1
  148. (read-string "1;`")
  149. ;=>1
  150. ;;; Hopefully less problematic characters can be checked together
  151. (read-string "1; &()*+,-./:;<=>?@[]^_{|}~")
  152. ;=>1
复制代码
  1. ;; Testing trivial macros
  2. (defmacro! one (fn* () 1))
  3. (one)
  4. ;=>1
  5. (defmacro! two (fn* () 2))
  6. (two)
  7. ;=>2
  8. ;; Testing unless macros
  9. (defmacro! unless (fn* (pred a b) `(if ~pred ~b ~a)))
  10. (unless false 7 8)
  11. ;=>7
  12. (unless true 7 8)
  13. ;=>8
  14. (defmacro! unless2 (fn* (pred a b) (list 'if (list 'not pred) a b)))
  15. (unless2 false 7 8)
  16. ;=>7
  17. (unless2 true 7 8)
  18. ;=>8
  19. ;; Testing macroexpand
  20. (macroexpand (one))
  21. ;=>1
  22. (macroexpand (unless PRED A B))
  23. ;=>(if PRED B A)
  24. (macroexpand (unless2 PRED A B))
  25. ;=>(if (not PRED) A B)
  26. (macroexpand (unless2 2 3 4))
  27. ;=>(if (not 2) 3 4)
  28. ;; Testing evaluation of macro result
  29. (defmacro! identity (fn* (x) x))
  30. (let* (a 123) (macroexpand (identity a)))
  31. ;=>a
  32. (let* (a 123) (identity a))
  33. ;=>123
  34. ;; Test that macros do not break empty list
  35. ()
  36. ;=>()
  37. ;; Test that macros do not break quasiquote
  38. `(1)
  39. ;=>(1)
  40. ;>>> deferrable=True
  41. ;;
  42. ;; -------- Deferrable Functionality --------
  43. ;; Testing non-macro function
  44. (not (= 1 1))
  45. ;=>false
  46. ;;; This should fail if it is a macro
  47. (not (= 1 2))
  48. ;=>true
  49. ;; Testing nth, first and rest functions
  50. (nth (list 1) 0)
  51. ;=>1
  52. (nth (list 1 2) 1)
  53. ;=>2
  54. (nth (list 1 2 nil) 2)
  55. ;=>nil
  56. (def! x "x")
  57. (def! x (nth (list 1 2) 2))
  58. x
  59. ;=>"x"
  60. (first (list))
  61. ;=>nil
  62. (first (list 6))
  63. ;=>6
  64. (first (list 7 8 9))
  65. ;=>7
  66. (rest (list))
  67. ;=>()
  68. (rest (list 6))
  69. ;=>()
  70. (rest (list 7 8 9))
  71. ;=>(8 9)
  72. ;; Testing cond macro
  73. (macroexpand (cond))
  74. ;=>nil
  75. (cond)
  76. ;=>nil
  77. (macroexpand (cond X Y))
  78. ;=>(if X Y (cond))
  79. (cond true 7)
  80. ;=>7
  81. (cond false 7)
  82. ;=>nil
  83. (macroexpand (cond X Y Z T))
  84. ;=>(if X Y (cond Z T))
  85. (cond true 7 true 8)
  86. ;=>7
  87. (cond false 7 true 8)
  88. ;=>8
  89. (cond false 7 false 8 "else" 9)
  90. ;=>9
  91. (cond false 7 (= 2 2) 8 "else" 9)
  92. ;=>8
  93. (cond false 7 false 8 false 9)
  94. ;=>nil
  95. ;; Testing EVAL in let*
  96. (let* (x (cond false "no" true "yes")) x)
  97. ;=>"yes"
  98. ;; Testing nth, first, rest with vectors
  99. (nth [1] 0)
  100. ;=>1
  101. (nth [1 2] 1)
  102. ;=>2
  103. (nth [1 2 nil] 2)
  104. ;=>nil
  105. (def! x "x")
  106. (def! x (nth [1 2] 2))
  107. x
  108. ;=>"x"
  109. (first [])
  110. ;=>nil
  111. (first nil)
  112. ;=>nil
  113. (first [10])
  114. ;=>10
  115. (first [10 11 12])
  116. ;=>10
  117. (rest [])
  118. ;=>()
  119. (rest nil)
  120. ;=>()
  121. (rest [10])
  122. ;=>()
  123. (rest [10 11 12])
  124. ;=>(11 12)
  125. (rest (cons 10 [11 12]))
  126. ;=>(11 12)
  127. ;; Testing EVAL in vector let*
  128. (let* [x (cond false "no" true "yes")] x)
  129. ;=>"yes"
  130. ;>>> soft=True
  131. ;>>> optional=True
  132. ;;
  133. ;; ------- Optional Functionality --------------
  134. ;; ------- (Not needed for self-hosting) -------
  135. ;; Test that macros use closures
  136. (def! x 2)
  137. (defmacro! a (fn* [] x))
  138. (a)
  139. ;=>2
  140. (let* (x 3) (a))
  141. ;=>2
复制代码
  1. ;;
  2. ;; Testing throw
  3. (throw "err1")
  4. ;/.*([Ee][Rr][Rr][Oo][Rr]|[Ee]xception).*err1.*
  5. ;;
  6. ;; Testing try*/catch*
  7. (try* 123 (catch* e 456))
  8. ;=>123
  9. (try* abc (catch* exc (prn "exc is:" exc)))
  10. ;/"exc is:" "'abc' not found"
  11. ;=>nil
  12. (try* (abc 1 2) (catch* exc (prn "exc is:" exc)))
  13. ;/"exc is:" "'abc' not found"
  14. ;=>nil
  15. ;; Make sure error from core can be caught
  16. (try* (nth () 1) (catch* exc (prn "exc is:" exc)))
  17. ;/"exc is:".*(length|range|[Bb]ounds|beyond).*
  18. ;=>nil
  19. (try* (throw "my exception") (catch* exc (do (prn "exc:" exc) 7)))
  20. ;/"exc:" "my exception"
  21. ;=>7
  22. ;; Test that exception handlers get restored correctly
  23. (try* (do (try* "t1" (catch* e "c1")) (throw "e1")) (catch* e "c2"))
  24. ;=>"c2"
  25. (try* (try* (throw "e1") (catch* e (throw "e2"))) (catch* e "c2"))
  26. ;=>"c2"
  27. ;;; Test that throw is a function:
  28. (try* (map throw (list "my err")) (catch* exc exc))
  29. ;=>"my err"
  30. ;;
  31. ;; Testing builtin functions
  32. (symbol? 'abc)
  33. ;=>true
  34. (symbol? "abc")
  35. ;=>false
  36. (nil? nil)
  37. ;=>true
  38. (nil? true)
  39. ;=>false
  40. (true? true)
  41. ;=>true
  42. (true? false)
  43. ;=>false
  44. (true? true?)
  45. ;=>false
  46. (false? false)
  47. ;=>true
  48. (false? true)
  49. ;=>false
  50. ;; Testing apply function with core functions
  51. (apply + (list 2 3))
  52. ;=>5
  53. (apply + 4 (list 5))
  54. ;=>9
  55. (apply prn (list 1 2 "3" (list)))
  56. ;/1 2 "3" \(\)
  57. ;=>nil
  58. (apply prn 1 2 (list "3" (list)))
  59. ;/1 2 "3" \(\)
  60. ;=>nil
  61. (apply list (list))
  62. ;=>()
  63. (apply symbol? (list (quote two)))
  64. ;=>true
  65. ;; Testing apply function with user functions
  66. (apply (fn* (a b) (+ a b)) (list 2 3))
  67. ;=>5
  68. (apply (fn* (a b) (+ a b)) 4 (list 5))
  69. ;=>9
  70. ;; Testing map function
  71. (def! nums (list 1 2 3))
  72. (def! double (fn* (a) (* 2 a)))
  73. (double 3)
  74. ;=>6
  75. (map double nums)
  76. ;=>(2 4 6)
  77. (map (fn* (x) (symbol? x)) (list 1 (quote two) "three"))
  78. ;=>(false true false)
  79. (= () (map str ()))
  80. ;=>true
  81. ;>>> deferrable=True
  82. ;;
  83. ;; ------- Deferrable Functionality ----------
  84. ;; ------- (Needed for self-hosting) -------
  85. ;; Testing symbol and keyword functions
  86. (symbol? :abc)
  87. ;=>false
  88. (symbol? 'abc)
  89. ;=>true
  90. (symbol? "abc")
  91. ;=>false
  92. (symbol? (symbol "abc"))
  93. ;=>true
  94. (keyword? :abc)
  95. ;=>true
  96. (keyword? 'abc)
  97. ;=>false
  98. (keyword? "abc")
  99. ;=>false
  100. (keyword? "")
  101. ;=>false
  102. (keyword? (keyword "abc"))
  103. ;=>true
  104. (symbol "abc")
  105. ;=>abc
  106. (keyword "abc")
  107. ;=>:abc
  108. ;; Testing sequential? function
  109. (sequential? (list 1 2 3))
  110. ;=>true
  111. (sequential? [15])
  112. ;=>true
  113. (sequential? sequential?)
  114. ;=>false
  115. (sequential? nil)
  116. ;=>false
  117. (sequential? "abc")
  118. ;=>false
  119. ;; Testing apply function with core functions and arguments in vector
  120. (apply + 4 [5])
  121. ;=>9
  122. (apply prn 1 2 ["3" 4])
  123. ;/1 2 "3" 4
  124. ;=>nil
  125. (apply list [])
  126. ;=>()
  127. ;; Testing apply function with user functions and arguments in vector
  128. (apply (fn* (a b) (+ a b)) [2 3])
  129. ;=>5
  130. (apply (fn* (a b) (+ a b)) 4 [5])
  131. ;=>9
  132. ;; Testing map function with vectors
  133. (map (fn* (a) (* 2 a)) [1 2 3])
  134. ;=>(2 4 6)
  135. (map (fn* [& args] (list? args)) [1 2])
  136. ;=>(true true)
  137. ;; Testing vector functions
  138. (vector? [10 11])
  139. ;=>true
  140. (vector? '(12 13))
  141. ;=>false
  142. (vector 3 4 5)
  143. ;=>[3 4 5]
  144. (= [] (vector))
  145. ;=>true
  146. (map? {})
  147. ;=>true
  148. (map? '())
  149. ;=>false
  150. (map? [])
  151. ;=>false
  152. (map? 'abc)
  153. ;=>false
  154. (map? :abc)
  155. ;=>false
  156. ;;
  157. ;; Testing hash-maps
  158. (hash-map "a" 1)
  159. ;=>{"a" 1}
  160. {"a" 1}
  161. ;=>{"a" 1}
  162. (assoc {} "a" 1)
  163. ;=>{"a" 1}
  164. (get (assoc (assoc {"a" 1 } "b" 2) "c" 3) "a")
  165. ;=>1
  166. (def! hm1 (hash-map))
  167. ;=>{}
  168. (map? hm1)
  169. ;=>true
  170. (map? 1)
  171. ;=>false
  172. (map? "abc")
  173. ;=>false
  174. (get nil "a")
  175. ;=>nil
  176. (get hm1 "a")
  177. ;=>nil
  178. (contains? hm1 "a")
  179. ;=>false
  180. (def! hm2 (assoc hm1 "a" 1))
  181. ;=>{"a" 1}
  182. (get hm1 "a")
  183. ;=>nil
  184. (contains? hm1 "a")
  185. ;=>false
  186. (get hm2 "a")
  187. ;=>1
  188. (contains? hm2 "a")
  189. ;=>true
  190. ;;; TODO: fix. Clojure returns nil but this breaks mal impl
  191. (keys hm1)
  192. ;=>()
  193. (= () (keys hm1))
  194. ;=>true
  195. (keys hm2)
  196. ;=>("a")
  197. (keys {"1" 1})
  198. ;=>("1")
  199. ;;; TODO: fix. Clojure returns nil but this breaks mal impl
  200. (vals hm1)
  201. ;=>()
  202. (= () (vals hm1))
  203. ;=>true
  204. (vals hm2)
  205. ;=>(1)
  206. (count (keys (assoc hm2 "b" 2 "c" 3)))
  207. ;=>3
  208. ;; Testing keywords as hash-map keys
  209. (get {:abc 123} :abc)
  210. ;=>123
  211. (contains? {:abc 123} :abc)
  212. ;=>true
  213. (contains? {:abcd 123} :abc)
  214. ;=>false
  215. (assoc {} :bcd 234)
  216. ;=>{:bcd 234}
  217. (keyword? (nth (keys {:abc 123 :def 456}) 0))
  218. ;=>true
  219. (keyword? (nth (vals {"a" :abc "b" :def}) 0))
  220. ;=>true
  221. ;; Testing whether assoc updates properly
  222. (def! hm4 (assoc {:a 1 :b 2} :a 3 :c 1))
  223. (get hm4 :a)
  224. ;=>3
  225. (get hm4 :b)
  226. ;=>2
  227. (get hm4 :c)
  228. ;=>1
  229. ;; Testing nil as hash-map values
  230. (contains? {:abc nil} :abc)
  231. ;=>true
  232. (assoc {} :bcd nil)
  233. ;=>{:bcd nil}
  234. ;;
  235. ;; Additional str and pr-str tests
  236. (str "A" {:abc "val"} "Z")
  237. ;=>"A{:abc val}Z"
  238. (str true "." false "." nil "." :keyw "." 'symb)
  239. ;=>"true.false.nil.:keyw.symb"
  240. (pr-str "A" {:abc "val"} "Z")
  241. ;=>"\"A\" {:abc \"val\"} \"Z\""
  242. (pr-str true "." false "." nil "." :keyw "." 'symb)
  243. ;=>"true \".\" false \".\" nil \".\" :keyw \".\" symb"
  244. (def! s (str {:abc "val1" :def "val2"}))
  245. (cond (= s "{:abc val1 :def val2}") true (= s "{:def val2 :abc val1}") true)
  246. ;=>true
  247. (def! p (pr-str {:abc "val1" :def "val2"}))
  248. (cond (= p "{:abc \"val1\" :def \"val2\"}") true (= p "{:def \"val2\" :abc \"val1\"}") true)
  249. ;=>true
  250. ;;
  251. ;; Test extra function arguments as Mal List (bypassing TCO with apply)
  252. (apply (fn* (& more) (list? more)) [1 2 3])
  253. ;=>true
  254. (apply (fn* (& more) (list? more)) [])
  255. ;=>true
  256. (apply (fn* (a & more) (list? more)) [1])
  257. ;=>true
  258. ;>>> soft=True
  259. ;>>> optional=True
  260. ;;
  261. ;; ------- Optional Functionality --------------
  262. ;; ------- (Not needed for self-hosting) -------
  263. ;; Testing throwing a hash-map
  264. (throw {:msg "err2"})
  265. ;/.*([Ee][Rr][Rr][Oo][Rr]|[Ee]xception).*msg.*err2.*
  266. ;;;TODO: fix so long lines don't trigger ANSI escape codes ;;;(try*
  267. ;;;(try* (throw ["data" "foo"]) (catch* exc (do (prn "exc is:" exc) 7))) ;;;;
  268. ;;;; "exc is:" ["data" "foo"] ;;;;=>7
  269. ;;;;=>7
  270. ;;
  271. ;; Testing try* without catch*
  272. (try* xyz)
  273. ;/.*\'?xyz\'? not found.*
  274. ;;
  275. ;; Testing throwing non-strings
  276. (try* (throw (list 1 2 3)) (catch* exc (do (prn "err:" exc) 7)))
  277. ;/"err:" \(1 2 3\)
  278. ;=>7
  279. ;;
  280. ;; Testing dissoc
  281. (def! hm3 (assoc hm2 "b" 2))
  282. (count (keys hm3))
  283. ;=>2
  284. (count (vals hm3))
  285. ;=>2
  286. (dissoc hm3 "a")
  287. ;=>{"b" 2}
  288. (dissoc hm3 "a" "b")
  289. ;=>{}
  290. (dissoc hm3 "a" "b" "c")
  291. ;=>{}
  292. (count (keys hm3))
  293. ;=>2
  294. (dissoc {:cde 345 :fgh 456} :cde)
  295. ;=>{:fgh 456}
  296. (dissoc {:cde nil :fgh 456} :cde)
  297. ;=>{:fgh 456}
  298. ;;
  299. ;; Testing equality of hash-maps
  300. (= {} {})
  301. ;=>true
  302. (= {} (hash-map))
  303. ;=>true
  304. (= {:a 11 :b 22} (hash-map :b 22 :a 11))
  305. ;=>true
  306. (= {:a 11 :b [22 33]} (hash-map :b [22 33] :a 11))
  307. ;=>true
  308. (= {:a 11 :b {:c 33}} (hash-map :b {:c 33} :a 11))
  309. ;=>true
  310. (= {:a 11 :b 22} (hash-map :b 23 :a 11))
  311. ;=>false
  312. (= {:a 11 :b 22} (hash-map :a 11))
  313. ;=>false
  314. (= {:a [11 22]} {:a (list 11 22)})
  315. ;=>true
  316. (= {:a 11 :b 22} (list :a 11 :b 22))
  317. ;=>false
  318. (= {} [])
  319. ;=>false
  320. (= [] {})
  321. ;=>false
  322. (keyword :abc)
  323. ;=>:abc
  324. (keyword? (first (keys {":abc" 123 ":def" 456})))
  325. ;=>false
  326. ;; Testing that hashmaps don't alter function ast
  327. (def! bar (fn* [a] {:foo (get a :foo)}))
  328. (bar {:foo (fn* [x] x)})
  329. (bar {:foo 3})
  330. ;; shouldn't give an error
复制代码
  1. ;;;
  2. ;;; See IMPL/tests/stepA_mal.mal for implementation specific
  3. ;;; interop tests.
  4. ;;;
  5. ;;
  6. ;; Testing readline
  7. (readline "mal-user> ")
  8. "hello"
  9. ;=>"\"hello\""
  10. ;;
  11. ;; Testing *host-language*
  12. ;;; each impl is different, but this should return false
  13. ;;; rather than throwing an exception
  14. (= "something bogus" *host-language*)
  15. ;=>false
  16. ;>>> deferrable=True
  17. ;;
  18. ;; ------- Deferrable Functionality ----------
  19. ;; ------- (Needed for self-hosting) -------
  20. ;;
  21. ;;
  22. ;; Testing hash-map evaluation and atoms (i.e. an env)
  23. (def! e (atom {"+" +}))
  24. (swap! e assoc "-" -)
  25. ( (get @e "+") 7 8)
  26. ;=>15
  27. ( (get @e "-") 11 8)
  28. ;=>3
  29. (swap! e assoc "foo" (list))
  30. (get @e "foo")
  31. ;=>()
  32. (swap! e assoc "bar" '(1 2 3))
  33. (get @e "bar")
  34. ;=>(1 2 3)
  35. ;; Testing for presence of optional functions
  36. (do (list time-ms string? number? seq conj meta with-meta fn?) nil)
  37. ;=>nil
  38. (map symbol? '(nil false true))
  39. ;=>(false false false)
  40. ;; ------------------------------------------------------------------
  41. ;>>> soft=True
  42. ;>>> optional=True
  43. ;;
  44. ;; ------- Optional Functionality --------------
  45. ;; ------- (Not needed for self-hosting) -------
  46. ;; Testing metadata on functions
  47. ;;
  48. ;; Testing metadata on mal functions
  49. (meta (fn* (a) a))
  50. ;=>nil
  51. (meta (with-meta (fn* (a) a) {"b" 1}))
  52. ;=>{"b" 1}
  53. (meta (with-meta (fn* (a) a) "abc"))
  54. ;=>"abc"
  55. (def! l-wm (with-meta (fn* (a) a) {"b" 2}))
  56. (meta l-wm)
  57. ;=>{"b" 2}
  58. (meta (with-meta l-wm {"new_meta" 123}))
  59. ;=>{"new_meta" 123}
  60. (meta l-wm)
  61. ;=>{"b" 2}
  62. (def! f-wm (with-meta (fn* [a] (+ 1 a)) {"abc" 1}))
  63. (meta f-wm)
  64. ;=>{"abc" 1}
  65. (meta (with-meta f-wm {"new_meta" 123}))
  66. ;=>{"new_meta" 123}
  67. (meta f-wm)
  68. ;=>{"abc" 1}
  69. (def! f-wm2 ^{"abc" 1} (fn* [a] (+ 1 a)))
  70. (meta f-wm2)
  71. ;=>{"abc" 1}
  72. ;; Meta of native functions should return nil (not fail)
  73. (meta +)
  74. ;=>nil
  75. ;;
  76. ;; Make sure closures and metadata co-exist
  77. (def! gen-plusX (fn* (x) (with-meta (fn* (b) (+ x b)) {"meta" 1})))
  78. (def! plus7 (gen-plusX 7))
  79. (def! plus8 (gen-plusX 8))
  80. (plus7 8)
  81. ;=>15
  82. (meta plus7)
  83. ;=>{"meta" 1}
  84. (meta plus8)
  85. ;=>{"meta" 1}
  86. (meta (with-meta plus7 {"meta" 2}))
  87. ;=>{"meta" 2}
  88. (meta plus8)
  89. ;=>{"meta" 1}
  90. ;;
  91. ;; Testing string? function
  92. (string? "")
  93. ;=>true
  94. (string? 'abc)
  95. ;=>false
  96. (string? "abc")
  97. ;=>true
  98. (string? :abc)
  99. ;=>false
  100. (string? (keyword "abc"))
  101. ;=>false
  102. (string? 234)
  103. ;=>false
  104. (string? nil)
  105. ;=>false
  106. ;; Testing number? function
  107. (number? 123)
  108. ;=>true
  109. (number? -1)
  110. ;=>true
  111. (number? nil)
  112. ;=>false
  113. (number? false)
  114. ;=>false
  115. (number? "123")
  116. ;=>false
  117. (def! add1 (fn* (x) (+ x 1)))
  118. ;; Testing fn? function
  119. (fn? +)
  120. ;=>true
  121. (fn? add1)
  122. ;=>true
  123. (fn? cond)
  124. ;=>false
  125. (fn? "+")
  126. ;=>false
  127. (fn? :+)
  128. ;=>false
  129. (fn? ^{"ismacro" true} (fn* () 0))
  130. ;=>true
  131. ;; Testing macro? function
  132. (macro? cond)
  133. ;=>true
  134. (macro? +)
  135. ;=>false
  136. (macro? add1)
  137. ;=>false
  138. (macro? "+")
  139. ;=>false
  140. (macro? :+)
  141. ;=>false
  142. (macro? {})
  143. ;=>false
  144. ;;
  145. ;; Testing conj function
  146. (conj (list) 1)
  147. ;=>(1)
  148. (conj (list 1) 2)
  149. ;=>(2 1)
  150. (conj (list 2 3) 4)
  151. ;=>(4 2 3)
  152. (conj (list 2 3) 4 5 6)
  153. ;=>(6 5 4 2 3)
  154. (conj (list 1) (list 2 3))
  155. ;=>((2 3) 1)
  156. (conj [] 1)
  157. ;=>[1]
  158. (conj [1] 2)
  159. ;=>[1 2]
  160. (conj [2 3] 4)
  161. ;=>[2 3 4]
  162. (conj [2 3] 4 5 6)
  163. ;=>[2 3 4 5 6]
  164. (conj [1] [2 3])
  165. ;=>[1 [2 3]]
  166. ;;
  167. ;; Testing seq function
  168. (seq "abc")
  169. ;=>("a" "b" "c")
  170. (apply str (seq "this is a test"))
  171. ;=>"this is a test"
  172. (seq '(2 3 4))
  173. ;=>(2 3 4)
  174. (seq [2 3 4])
  175. ;=>(2 3 4)
  176. (seq "")
  177. ;=>nil
  178. (seq '())
  179. ;=>nil
  180. (seq [])
  181. ;=>nil
  182. (seq nil)
  183. ;=>nil
  184. ;;
  185. ;; Testing metadata on collections
  186. (meta [1 2 3])
  187. ;=>nil
  188. (with-meta [1 2 3] {"a" 1})
  189. ;=>[1 2 3]
  190. (meta (with-meta [1 2 3] {"a" 1}))
  191. ;=>{"a" 1}
  192. (vector? (with-meta [1 2 3] {"a" 1}))
  193. ;=>true
  194. (meta (with-meta [1 2 3] "abc"))
  195. ;=>"abc"
  196. (with-meta [] "abc")
  197. ;=>[]
  198. (meta (with-meta (list 1 2 3) {"a" 1}))
  199. ;=>{"a" 1}
  200. (list? (with-meta (list 1 2 3) {"a" 1}))
  201. ;=>true
  202. (with-meta (list) {"a" 1})
  203. ;=>()
  204. (empty? (with-meta (list) {"a" 1}))
  205. ;=>true
  206. (meta (with-meta {"abc" 123} {"a" 1}))
  207. ;=>{"a" 1}
  208. (map? (with-meta {"abc" 123} {"a" 1}))
  209. ;=>true
  210. (with-meta {} {"a" 1})
  211. ;=>{}
  212. (def! l-wm (with-meta [4 5 6] {"b" 2}))
  213. ;=>[4 5 6]
  214. (meta l-wm)
  215. ;=>{"b" 2}
  216. (meta (with-meta l-wm {"new_meta" 123}))
  217. ;=>{"new_meta" 123}
  218. (meta l-wm)
  219. ;=>{"b" 2}
  220. ;;
  221. ;; Testing metadata on builtin functions
  222. (meta +)
  223. ;=>nil
  224. (def! f-wm3 ^{"def" 2} +)
  225. (meta f-wm3)
  226. ;=>{"def" 2}
  227. (meta +)
  228. ;=>nil
  229. ;; Loading sumdown from computations.mal
  230. (load-file "../tests/computations.mal")
  231. ;=>nil
  232. ;;
  233. ;; Testing time-ms function
  234. (def! start-time (time-ms))
  235. (= start-time 0)
  236. ;=>false
  237. (sumdown 10) ; Waste some time
  238. ;=>55
  239. (> (time-ms) start-time)
  240. ;=>true
  241. ;;
  242. ;; Test that defining a macro does not mutate an existing function.
  243. (def! f (fn* [x] (number? x)))
  244. (defmacro! m f)
  245. (f (+ 1 1))
  246. ;=>true
  247. (m (+ 1 1))
  248. ;=>false
复制代码
2

评分人数

    • HOPE2021: 感谢分享!技术 + 1
    • CrLf: 大工程PB + 8 技术 + 1

TOP

牛逼

TOP

回复 4# CrLf


    其实准备再用bat写一遍(还没动手

TOP

回复 6# jyswjjgdwtdtj


    今天发现个陈年老BUG,刚才才给修了,自己挖自己的坟帖了属于是(

TOP

返回列表