Przeglądaj źródła

Add strings and preprocessor directives

Matt Coles 9 lat temu
rodzic
commit
4a33498b85
3 zmienionych plików z 61 dodań i 2 usunięć
  1. 4 0
      README.md
  2. 51 1
      compiler.js
  3. 6 1
      example.mc

+ 4 - 0
README.md

6
 they should be from `example.mc`. A `;` denotes that the rest of the line (until the compiler sees `\n`) as a comment and 
6
 they should be from `example.mc`. A `;` denotes that the rest of the line (until the compiler sees `\n`) as a comment and 
7
 means that it will not be compiled.
7
 means that it will not be compiled.
8
 
8
 
9
+In addition to the regular include(coming soon), there is also a preprocessing directive called `` `source <filename> `` which can be used 
10
+to just directly insert the contents of `<filename>` into the file. Instead of wasting the compilers energy checking for circular
11
+sources, you have two options, to not be so stupid or wait for the call stack to overflow.
12
+
9
 The compiler runs like `node compiler.js file.mc` where `file.mc` is the file you wish to compile, and this will produce an
13
 The compiler runs like `node compiler.js file.mc` where `file.mc` is the file you wish to compile, and this will produce an
10
 `output.js` which requires `stdlib.js` to be in the same directory when running for now at least.
14
 `output.js` which requires `stdlib.js` to be in the same directory when running for now at least.
11
 
15
 

+ 51 - 1
compiler.js

1
 const fs = require('fs')
1
 const fs = require('fs')
2
 
2
 
3
+var preprocess = function (input) {
4
+  let inputArr = input.split('\n')
5
+  for (i = 0; i < inputArr.length; i++) {
6
+    line = inputArr[i]
7
+    if (line.startsWith('`source')) {
8
+      line = fs.readFileSync(line.split(' ')[1], { encoding: 'utf-8' })
9
+      inputArr[i] = preprocess(line)
10
+    }
11
+  }
12
+  return inputArr.join('\n')
13
+}
14
+
3
 var tokenizer = function (input) {
15
 var tokenizer = function (input) {
4
   let pos = 0
16
   let pos = 0
5
   let tokens = []
17
   let tokens = []
30
       }
42
       }
31
       continue
43
       continue
32
     }
44
     }
45
+    let stringChars = /['"]/
46
+    if (stringChars.test(char)) {
47
+      let myDelim = char
48
+      let stringString = ''
49
+      char = input[++pos]
50
+      while (char !== myDelim) {
51
+        if (char !== '\n') {
52
+          stringString += char
53
+        }
54
+        char = input[++pos]
55
+      }
56
+      pos++
57
+      tokens.push({
58
+        type: 'string',
59
+        value: stringString
60
+      })
61
+      continue
62
+    }
33
     let numbers = /[0-9]/
63
     let numbers = /[0-9]/
34
     if (numbers.test(char)) {
64
     if (numbers.test(char)) {
35
       let numberString = ''
65
       let numberString = ''
110
       }
140
       }
111
     }
141
     }
112
 
142
 
143
+    if (token.type === 'string') {
144
+      pos++
145
+      return {
146
+        type: 'StringLiteral',
147
+        value: token.value
148
+      }
149
+    }
150
+
113
     if (token.type === 'paren' && token.value == '(') {
151
     if (token.type === 'paren' && token.value == '(') {
114
       token = input[++pos]
152
       token = input[++pos]
115
       if (token.type !== 'name') {
153
       if (token.type !== 'name') {
171
         break
209
         break
172
       case 'NumberLiteral':
210
       case 'NumberLiteral':
173
         break
211
         break
212
+      case 'StringLiteral':
213
+        break
174
       case 'DollarVar':
214
       case 'DollarVar':
175
         break
215
         break
176
       default:
216
       default:
200
         value: node.value
240
         value: node.value
201
       })
241
       })
202
     },
242
     },
243
+    StringLiteral: function (node, parent) {
244
+      parent._context.push({
245
+        type: 'StringLiteral',
246
+        value: node.value
247
+      })
248
+    },
203
     VariableReference: function (node, parent) {
249
     VariableReference: function (node, parent) {
204
       parent._context.push({
250
       parent._context.push({
205
         type: 'VariableReference',
251
         type: 'VariableReference',
277
     case 'NumberLiteral':
323
     case 'NumberLiteral':
278
       return '{value: ' + node.value + '}'
324
       return '{value: ' + node.value + '}'
279
       break
325
       break
326
+    case 'StringLiteral':
327
+      return '{ value: \'' + node.value + '\' }'
328
+      break
280
     default:
329
     default:
281
       throw {
330
       throw {
282
         name: 'Compiler Error',
331
         name: 'Compiler Error',
290
 
339
 
291
 // const myInput = '(assign twelve 12) (assign myvar (add twelve (subtract 6 2))) (log myvar)'
340
 // const myInput = '(assign twelve 12) (assign myvar (add twelve (subtract 6 2))) (log myvar)'
292
 const myInput = fs.readFileSync(process.argv[2], { encoding: 'utf-8' })
341
 const myInput = fs.readFileSync(process.argv[2], { encoding: 'utf-8' })
293
-const myTokens = tokenizer(myInput)
342
+const preProcessedInput = preprocess(myInput)
343
+const myTokens = tokenizer(preProcessedInput)
294
 const parsedTree = parser(myTokens)
344
 const parsedTree = parser(myTokens)
295
 const transformedTree = transformer(parsedTree)
345
 const transformedTree = transformer(parsedTree)
296
 //console.log(JSON.stringify(transformedTree,null,2))
346
 //console.log(JSON.stringify(transformedTree,null,2))

+ 6 - 1
example.mc

18
 (myF) ; Calling an argument-less function
18
 (myF) ; Calling an argument-less function
19
 (log 0)
19
 (log 0)
20
 (log 0)
20
 (log 0)
21
-(log 1)
22
 (log 0)
21
 (log 0)
23
 (log 0)
22
 (log 0)
24
 (log 0)
23
 (log 0)
25
 (argTest 43 scopelol) ; Custom functions with arguments are called like any other
24
 (argTest 43 scopelol) ; Custom functions with arguments are called like any other
25
+(log "We got a string!")
26
+(argTest "You can call functions with strings!" "Yay!")
27
+(log "It supports multiline stri
28
+ngs without stupid escape 
29
+
30
+characters")