Przeglądaj źródła

Refactor standard libraries and add namespacing

Matt Coles 9 lat temu
rodzic
commit
d3a4826766
5 zmienionych plików z 83 dodań i 14 usunięć
  1. 22 6
      compiler.js
  2. 2 0
      example.mc
  3. 6 2
      fizzbuzz.mc
  4. 16 6
      stdlib.js
  5. 37 0
      lib/str.js

+ 22 - 6
compiler.js

@@ -81,7 +81,7 @@ var tokenizer = function (input) {
81 81
       })
82 82
       continue
83 83
     }
84
-    let characters = /[a-zA-Z_]/
84
+    let characters = /[a-zA-Z_:]/
85 85
     if (characters.test(char)) {
86 86
       let name = ''
87 87
       while (characters.test(char)) {
@@ -312,7 +312,7 @@ var generator = function (node) {
312 312
   switch (node.type) {
313 313
     case 'Prog':
314 314
       let program = node.body.map(generator)
315
-      program.unshift('var _ = require("./stdlib.js")')
315
+      program.unshift('var _ = require("./lib/stdlib.js")(this)')
316 316
       return program.join('\n')
317 317
       break
318 318
     case 'Statement':
@@ -320,16 +320,27 @@ var generator = function (node) {
320 320
       break
321 321
     case 'FunctionCall':
322 322
       if (!node.callee.name.match('(def|if|repeat)')) {
323
-        return (generator(node.callee) + '(' + node.args.map(generator).join(', ') + ')')
323
+        if (node.callee.name.match('include')) {
324
+          // Include is a special function and we will write the generation ourselves
325
+          if (node.args.length > 1) {
326
+            console.error("Compiler Error: (include) may only take 1 argument!")
327
+            process.exit(1)
328
+          } else {
329
+            let lib = './lib/' + node.args[0].value + '.js'
330
+            return ('var _' + node.args[0].value + ' = require("' + lib + '")(this)')
331
+          }
332
+        } else {
333
+          return (generator(node.callee) + '(' + node.args.map(generator).join(', ') + ')')
334
+        }
324 335
       } else {
325 336
         return (generator(node.callee) + '(' + node.args.map((v, i) => {
326 337
           if (i === 0) {
327 338
             return generator(v) + ', '
328 339
           } else {
329 340
             if (i === 1) {
330
-              return 'function() {' + generator(v) + ';'
341
+              return 'function() { \n' + generator(v) + ';\n'
331 342
             } else {
332
-              return generator(v) + '; '
343
+              return generator(v) + ';\n'
333 344
             }
334 345
           }
335 346
         }).join('') + '})')
@@ -342,7 +353,12 @@ var generator = function (node) {
342 353
       return '}, function() {'
343 354
       break
344 355
     case 'FunctionName':
345
-      return '_.' + node.name
356
+      if (node.name.match("::")) {
357
+        let [namespace, func] = node.name.split("::")
358
+        return "_" + namespace + "." + func
359
+      } else {
360
+        return '_.' + node.name
361
+      }
346 362
       break
347 363
     case 'VariableReference':
348 364
       return '_.ref(\'' + node.value + '\')'

+ 2 - 0
example.mc

@@ -1,4 +1,5 @@
1 1
 ; This is a test program
2
+(include str)
2 3
 (assign twelve 12) ; This assigns the variable twelve, to the number literal 12
3 4
 (assign myvar (add twelve (subtract 6 2))) ; This assigns the variable myvar, to the result of adding the variable twelve to the result of subtracting 2 from 6
4 5
 (log myvar) ; This logs the value of myvar
@@ -32,3 +33,4 @@ characters")
32 33
 (log scopelol)
33 34
 (repeat scopelol (log 10))
34 35
 (if (eq 2 scopelol) (log "2 == scopelol") | (log "2 != scopelol"))
36
+(log (str::concat "Hello " "World!"))

+ 6 - 2
fizzbuzz.mc

@@ -1,8 +1,12 @@
1
+(include str)
1 2
 (def fizzbuzz
2 3
   (assign i 1)
3 4
   (repeat $1
4
-    (if (eq (modulo i 3) 0) (if (eq (modulo i 5) 0) (log "FizzBuzz") | (log "Fizz")))
5
-    (if (eq (modulo i 5) 0) (log "Buzz") | (log i))
5
+    (assign result "")
6
+    (if (eq (modulo i 3) 0) (assign result (str::concat result "Fizz")))
7
+    (if (eq (modulo i 5) 0) (assign result (str::concat result "Buzz")))
8
+    (if (eq result "") (assign result i))
9
+    (log result)
6 10
     (assign i (add i 1))
7 11
   )
8 12
 )

+ 16 - 6
stdlib.js

@@ -36,8 +36,8 @@ const builtins = {
36 36
     function_defs[prop.name] = body;
37 37
   },
38 38
   repeat: function (amount, body) {
39
-    for (i = 0 ; i < amount.value; i++) {
40
-        body() 
39
+    for (ii = 0 ; ii < amount.value; ii++) {
40
+        body.bind(_)() 
41 41
     }
42 42
   },
43 43
   eQ: function (arg1, arg2) {
@@ -52,13 +52,19 @@ const builtins = {
52 52
   },
53 53
   if: function (pred, body_true, body_false) {
54 54
     if (pred.value) {
55
-      body_true()
55
+      body_true.bind(_)()
56 56
     } else {
57 57
       if (body_false) {
58
-        body_false()
58
+        body_false.bind(_)()
59 59
       }
60 60
     }
61 61
   },
62
+  and: function (pred1, pred2) {
63
+    return pred1 && pred2
64
+  },
65
+  or: function (pred1, pred2) { 
66
+    return pred1 || pred2
67
+  },
62 68
   modulo: function (arg1, arg2) {
63 69
     return {
64 70
       value: (arg1.value % arg2.value)
@@ -88,6 +94,10 @@ const my_handler = {
88 94
   }
89 95
 }
90 96
 
91
-const _ = new Proxy({}, my_handler)
97
+const proxy_obj = new Proxy({}, my_handler)
98
+let _
92 99
 
93
-module.exports = _
100
+module.exports = function (self) {
101
+  _ = self
102
+  return proxy_obj
103
+}

+ 37 - 0
lib/str.js

@@ -0,0 +1,37 @@
1
+const global_obj = {}
2
+const function_defs = {}
3
+const warnings = {}
4
+const builtins = {
5
+  concat: function () {
6
+    let str = ""
7
+    for (i = 0; i < arguments.length; i++) {
8
+      str += arguments[i].value
9
+    }
10
+    return {
11
+      value: str
12
+    }
13
+  }
14
+}
15
+
16
+const my_handler = {
17
+  get: function (target, prop) {
18
+    let methods = Object.keys(builtins)
19
+    if (methods.includes(prop)) {
20
+      return builtins[prop]
21
+    } else {
22
+      console.error("Undefined function call! No such function: ", prop)
23
+    }
24
+  }, 
25
+  set: function (target, prop, data) {
26
+    if (prop === 'w') data.map((w) => warnings.w = true)
27
+    else console.error("Attempting to set unknown property on interpreter! How did you do that?")
28
+  }
29
+}
30
+
31
+const proxy_obj = new Proxy({}, my_handler)
32
+let _
33
+
34
+module.exports = function (self) {
35
+  _ = self
36
+  return proxy_obj
37
+}