Last active
August 29, 2015 14:09
-
-
Save CMCDragonkai/44f43858afd78394f023 to your computer and use it in GitHub Desktop.
OMetaJS: FizzBuzz Compiler
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// our FizzBuzz language | |
var code = | |
"for every number from 1 to 100\ | |
if the number is a multiple of 3 and it is a multiple of 5 then\ | |
print \"FizzBuzz\"\ | |
else if it is a multiple of 3 then\ | |
print \"Fizz\"\ | |
else if it is a multiple of 5 then\ | |
print \"Buzz\"\ | |
else\ | |
print the number\ | |
"; | |
ometa FizzBuzz { | |
// number is overwritten to parse digit characters and return them as a string | |
number = spaces ('+' | '-' | empty):prefix digit+:ds -> ( | |
parseInt( | |
(prefix.length > 0) ? | |
prefix + ds.join('') : | |
ds.join('') | |
) | |
), | |
// quotedString matches strings inside quotes | |
quotedString = spaces '"' (~'"' anything)*:string '"' -> ( | |
string.length == 0 ? | |
"" : | |
string.join("") | |
), | |
// variables can be prefixed with `the`, we need to track it as `_it` in the state table so it can be referenced again | |
variableName = | |
("the" | empty) spaces | |
firstAndRest('letter', 'letterOrDigit'):x | |
!(self.set("_it", x.join(""))) | |
-> (x.join("")), | |
// expressions are either an andExpression, multipleExpression, numberExpression or a quotedString | |
// all expressions are translated into functions | |
expression = andExpression | |
| multipleExpression | |
| numberExpression | |
| quotedString:qs -> (function () { return qs; }), | |
// and expressions are left recursive allowing nested and expressions, and they evaluate into a function returning a boolean | |
andExpression = andExpression:l "and" booleanExpression:r -> ( | |
function () { | |
return !!l() && !!r(); | |
} | |
) | |
| booleanExpression, | |
// a boolean expression is just a boolean function | |
booleanExpression = expression:e -> (function () { | |
var object = e(); | |
if (typeof object == "boolean") { | |
return object; | |
} else if (typeof o == "number") { | |
return object != 0; | |
} else { | |
return (String(object).length > 0) && object !== null && object !== undefined; | |
} | |
}), | |
// number expressions are functions that return an integers | |
// this is where `_it` can be resolved from the previously assigned `the` | |
numberExpression = number:n -> (function () { | |
return parseInt(n); | |
}) | |
| "it" -> (function () { | |
return parseInt( | |
self.get( | |
self.get("_it") | |
) | |
); | |
}) | |
| variableName:vn -> (function () { | |
return parseInt(self.get(vn)); | |
}), | |
// `is a multiple of` is a primitive infix operator | |
multipleExpression = numberExpression:left "is a multiple of" numberExpression:right -> ( | |
function () { | |
return (left() % right()) == 0; | |
} | |
), | |
// statements represent top expressions | |
// we have `print`, `if then else` and `for every` | |
statement = "print" expression:e -> (function () { console.log(e()); }) | |
| "if" andExpression:condition "then" statement:first ("else" statement | empty):second -> ( | |
function () { | |
if (condition()) { | |
first(); | |
} else if (String(second).length > 0 && second != null) { | |
second(); | |
} | |
} | |
) | |
| "for every" variableName:vn "from" number:low "to" number:high statement:s -> ( | |
function () { | |
for (var i = low; i <= high; i++) { | |
self.set(vn, i); | |
s(); | |
} | |
} | |
), | |
// a block is zero or more statements | |
block = statement*:ss -> ( | |
function () { | |
ss.forEach(function (statement) { | |
statement(); | |
}); | |
} | |
), | |
// end of file is any number of spaces then an end | |
EOF = spaces end, | |
// our program is just one block! | |
program = block:b EOF -> (b) | |
} | |
FizzBuzz.initialize = function() { | |
// our global state table | |
this.vars = {}; | |
this.set = function(k, v){ | |
this.vars[k] = v; | |
return this; | |
}; | |
this.get = function(k) { | |
return this.vars[k]; | |
}; | |
}; | |
// compiles our language into JavaScript with the top level program rule | |
var result = FizzBuzz.matchAll( | |
code, | |
'program' | |
); | |
// execute the code! | |
result(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 | |
2 | |
Fizz | |
4 | |
Buzz | |
Fizz | |
7 | |
8 | |
Fizz | |
Buzz | |
11 | |
Fizz | |
13 | |
14 | |
FizzBuzz | |
16 | |
17 | |
Fizz | |
19 | |
Buzz | |
Fizz | |
22 | |
23 | |
Fizz | |
Buzz | |
26 | |
Fizz | |
28 | |
29 | |
FizzBuzz | |
31 | |
32 | |
Fizz | |
34 | |
Buzz | |
Fizz | |
37 | |
38 | |
Fizz | |
Buzz | |
41 | |
Fizz | |
43 | |
44 | |
FizzBuzz | |
46 | |
47 | |
Fizz | |
49 | |
Buzz | |
Fizz | |
52 | |
53 | |
Fizz | |
Buzz | |
56 | |
Fizz | |
58 | |
59 | |
FizzBuzz | |
61 | |
62 | |
Fizz | |
64 | |
Buzz | |
Fizz | |
67 | |
68 | |
Fizz | |
Buzz | |
71 | |
Fizz | |
73 | |
74 | |
FizzBuzz | |
76 | |
77 | |
Fizz | |
79 | |
Buzz | |
Fizz | |
82 | |
83 | |
Fizz | |
Buzz | |
86 | |
Fizz | |
88 | |
89 | |
FizzBuzz | |
91 | |
92 | |
Fizz | |
94 | |
Buzz | |
Fizz | |
97 | |
98 | |
Fizz | |
Buzz |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment