浏览代码

Add function definitions and more example code to showcase this

Matt Coles 9 年之前
父节点
当前提交
b1a75b62e7
共有 3 个文件被更改,包括 107 次插入2 次删除
  1. 54 1
      compiler.js
  2. 18 0
      example.mc
  3. 35 1
      stdlib.js

+ 54 - 1
compiler.js

@@ -56,6 +56,25 @@ var tokenizer = function (input) {
56 56
       })
57 57
       continue
58 58
     }
59
+    let dollar = /[$]/
60
+    if (dollar.test(char)) {
61
+      let name = ''
62
+      char = input[++pos]
63
+      if (numbers.test(char)) {
64
+        while (numbers.test(char)) {
65
+          name += char
66
+          char = input[++pos]
67
+        }
68
+      } else {
69
+        console.error("Compiler Error: $ must be followed by a digit [0-9]")
70
+        process.exit(1);
71
+      }
72
+      tokens.push({
73
+        type: 'dollar',
74
+        value: name
75
+      })
76
+      continue
77
+    }
59 78
     throw new TypeError("I'm not sure what you are telling me :( Ask my creator to teach me what a: " + char + " is.")
60 79
   }
61 80
   return tokens
@@ -83,6 +102,14 @@ var parser = function (input) {
83 102
       }
84 103
     }
85 104
 
105
+    if (token.type === 'dollar') {
106
+      pos++
107
+      return {
108
+        type: 'DollarVar',
109
+        value: token.value
110
+      }
111
+    }
112
+
86 113
     if (token.type === 'paren' && token.value == '(') {
87 114
       token = input[++pos]
88 115
       if (token.type !== 'name') {
@@ -144,6 +171,8 @@ var traverser = function (ast, visitor) {
144 171
         break
145 172
       case 'NumberLiteral':
146 173
         break
174
+      case 'DollarVar':
175
+        break
147 176
       default:
148 177
         throw {
149 178
           name: 'Compiler Error',
@@ -177,6 +206,12 @@ var transformer = function (ast) {
177 206
         value: node.value
178 207
       })
179 208
     },
209
+    DollarVar: function (node, parent) {
210
+      parent._context.push({
211
+        type: 'DollarVar',
212
+        value: node.value
213
+      })
214
+    },
180 215
     FunctionCall: function (node, parent) {
181 216
       let expression = {
182 217
         type: 'FunctionCall',
@@ -214,7 +249,24 @@ var generator = function (node) {
214 249
       return (generator(node.expr) + ';')
215 250
       break
216 251
     case 'FunctionCall':
217
-      return (generator(node.callee) + '(' + node.args.map(generator).join(', ') + ')')
252
+      if (node.callee.name !== 'def') {
253
+        return (generator(node.callee) + '(' + node.args.map(generator).join(', ') + ')')
254
+      } else {
255
+        return (generator(node.callee) + '(' + node.args.map((v, i) => {
256
+          if (i === 0) {
257
+            return generator(v) + ', '
258
+          } else {
259
+            if (i === 1) {
260
+              return "'" + generator(v) + '; '
261
+            } else {
262
+              return generator(v) + '; '
263
+            }
264
+          }
265
+        }).join('') + "')")
266
+      }
267
+      break;
268
+    case 'DollarVar':
269
+      return '$' + node.value
218 270
       break
219 271
     case 'FunctionName':
220 272
       return '_.' + node.name
@@ -241,5 +293,6 @@ const myInput = fs.readFileSync(process.argv[2], { encoding: 'utf-8' })
241 293
 const myTokens = tokenizer(myInput)
242 294
 const parsedTree = parser(myTokens)
243 295
 const transformedTree = transformer(parsedTree)
296
+//console.log(JSON.stringify(transformedTree,null,2))
244 297
 const output = generator(transformedTree)
245 298
 fs.writeFileSync('output.js', output)

+ 18 - 0
example.mc

@@ -5,3 +5,21 @@
5 5
 (log 6) # This logs the number literal 6
6 6
 (assign twelve myvar) # This reassigns the variable twelve to the value of the variable myvar
7 7
 (log twelve) # This logs the new value of the variable twelve
8
+# An example function definition
9
+(def myF 
10
+  (log 0) 
11
+  (log twelve) 
12
+  (log 6) 
13
+  (log 6) 
14
+  (assign scopelol (add twelve 5)) 
15
+  (log scopelol)
16
+)
17
+(def argTest (log $1) (log $2)) # Functions take an unlimited number of arguments that can be referred to by $n
18
+(myF) # Calling an argument-less function
19
+(log 0)
20
+(log 0)
21
+(log 0)
22
+(log 0)
23
+(log 0)
24
+(log 0)
25
+(argTest 43 scopelol) # Custom functions with arguments are called like any other

+ 35 - 1
stdlib.js

@@ -1,5 +1,7 @@
1 1
 const global_obj = {}
2
-module.exports = {
2
+const function_defs = {}
3
+const warnings = {}
4
+const builtins = {
3 5
   assign: function (ref, value) {
4 6
     if (!ref.name) {
5 7
       console.error('Argument 1 of assign must always be a VariableReference')
@@ -25,5 +27,37 @@ module.exports = {
25 27
       name: refname,
26 28
       value: global_obj[refname]
27 29
     }
30
+  },
31
+  def: function (prop, body) {
32
+    let methods = Object.keys(function_defs)
33
+    if (methods.includes(prop.name)) {
34
+      console.warn("Warning! Redefining function, did you mean to do this?")
35
+    }
36
+    function_defs[prop.name] = body;
37
+  }
38
+}
39
+
40
+
41
+const my_handler = {
42
+  get: function (target, prop) {
43
+    let methods = Object.keys(builtins)
44
+    if (methods.includes(prop)) {
45
+      return builtins[prop]
46
+    } else {
47
+      methods = Object.keys(function_defs)
48
+      if (methods.includes(prop)) {
49
+        return (function () { eval(function_defs[prop].replace(/\$(\d+)/g, (m, n) => JSON.stringify(arguments[(+n-1)]))) })
50
+      } else {
51
+        console.error("Undefined function call! No such function: ", prop)
52
+      }
53
+    }
54
+  }, 
55
+  set: function (target, prop, data) {
56
+    if (prop === 'w') data.map((w) => warnings.w = true)
57
+    else console.error("Attempting to set unknown property on interpreter! How did you do that?")
28 58
   }
29 59
 }
60
+
61
+const _ = new Proxy({}, my_handler)
62
+
63
+module.exports = _