mirror of
https://github.com/jamiebuilds/the-super-tiny-compiler.git
synced 2024-10-27 20:34:08 +00:00
Part 1: the lexer
This commit is contained in:
parent
110068e7a5
commit
b14161b025
282
lib/js/src/compiler.js
Normal file
282
lib/js/src/compiler.js
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
// Generated by BUCKLESCRIPT VERSION 1.9.3, PLEASE EDIT WITH CARE
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var List = require("bs-platform/lib/js/list.js");
|
||||||
|
var Block = require("bs-platform/lib/js/block.js");
|
||||||
|
var $$String = require("bs-platform/lib/js/string.js");
|
||||||
|
var Caml_string = require("bs-platform/lib/js/caml_string.js");
|
||||||
|
var Js_primitive = require("bs-platform/lib/js/js_primitive.js");
|
||||||
|
|
||||||
|
function explode(s) {
|
||||||
|
var _i = s.length - 1 | 0;
|
||||||
|
var _l = /* [] */0;
|
||||||
|
while(true) {
|
||||||
|
var l = _l;
|
||||||
|
var i = _i;
|
||||||
|
if (i < 0) {
|
||||||
|
return l;
|
||||||
|
} else {
|
||||||
|
_l = /* :: */[
|
||||||
|
Caml_string.get(s, i),
|
||||||
|
l
|
||||||
|
];
|
||||||
|
_i = i - 1 | 0;
|
||||||
|
continue ;
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function tokenizer(input) {
|
||||||
|
var _input = explode(input);
|
||||||
|
var _current = /* None */0;
|
||||||
|
var _tokens = /* [] */0;
|
||||||
|
while(true) {
|
||||||
|
var tokens = _tokens;
|
||||||
|
var current = _current;
|
||||||
|
var input$1 = _input;
|
||||||
|
if (input$1) {
|
||||||
|
var head = List.hd(input$1);
|
||||||
|
var tail = List.tl(input$1);
|
||||||
|
var exit = 0;
|
||||||
|
var exit$1 = 0;
|
||||||
|
var exit$2 = 0;
|
||||||
|
var switcher = head - 32 | 0;
|
||||||
|
if (switcher > 9 || switcher < 0) {
|
||||||
|
exit$2 = 3;
|
||||||
|
} else {
|
||||||
|
switch (switcher) {
|
||||||
|
case 0 :
|
||||||
|
if (current) {
|
||||||
|
var match = current[0];
|
||||||
|
if (typeof match === "number") {
|
||||||
|
exit$1 = 2;
|
||||||
|
} else {
|
||||||
|
switch (match.tag | 0) {
|
||||||
|
case 0 :
|
||||||
|
_tokens = /* :: */[
|
||||||
|
/* Number */Block.__(0, [match[0]]),
|
||||||
|
tokens
|
||||||
|
];
|
||||||
|
_current = /* None */0;
|
||||||
|
_input = tail;
|
||||||
|
continue ;
|
||||||
|
case 1 :
|
||||||
|
exit$2 = 3;
|
||||||
|
break;
|
||||||
|
case 2 :
|
||||||
|
_tokens = /* :: */[
|
||||||
|
/* Name */Block.__(2, [match[0]]),
|
||||||
|
tokens
|
||||||
|
];
|
||||||
|
_current = /* None */0;
|
||||||
|
_input = tail;
|
||||||
|
continue ;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
exit$1 = 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2 :
|
||||||
|
if (current) {
|
||||||
|
var match$1 = current[0];
|
||||||
|
if (typeof match$1 === "number") {
|
||||||
|
return List.rev(tokens);
|
||||||
|
} else if (match$1.tag === 1) {
|
||||||
|
_tokens = /* :: */[
|
||||||
|
/* String */Block.__(1, [match$1[0]]),
|
||||||
|
tokens
|
||||||
|
];
|
||||||
|
_current = /* None */0;
|
||||||
|
_input = tail;
|
||||||
|
continue ;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return List.rev(tokens);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_current = /* Some */[/* String */Block.__(1, [""])];
|
||||||
|
_input = tail;
|
||||||
|
continue ;
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1 :
|
||||||
|
case 3 :
|
||||||
|
case 4 :
|
||||||
|
case 5 :
|
||||||
|
case 6 :
|
||||||
|
case 7 :
|
||||||
|
exit$2 = 3;
|
||||||
|
break;
|
||||||
|
case 8 :
|
||||||
|
if (current) {
|
||||||
|
exit$2 = 3;
|
||||||
|
} else {
|
||||||
|
_tokens = /* :: */[
|
||||||
|
/* OpenParen */0,
|
||||||
|
tokens
|
||||||
|
];
|
||||||
|
_current = /* None */0;
|
||||||
|
_input = tail;
|
||||||
|
continue ;
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 9 :
|
||||||
|
if (current) {
|
||||||
|
var match$2 = current[0];
|
||||||
|
if (typeof match$2 === "number") {
|
||||||
|
return List.rev(tokens);
|
||||||
|
} else {
|
||||||
|
switch (match$2.tag | 0) {
|
||||||
|
case 0 :
|
||||||
|
_tokens = /* :: */[
|
||||||
|
/* CloseParen */1,
|
||||||
|
/* :: */[
|
||||||
|
/* Number */Block.__(0, [match$2[0]]),
|
||||||
|
tokens
|
||||||
|
]
|
||||||
|
];
|
||||||
|
_current = /* None */0;
|
||||||
|
_input = tail;
|
||||||
|
continue ;
|
||||||
|
case 1 :
|
||||||
|
exit$2 = 3;
|
||||||
|
break;
|
||||||
|
case 2 :
|
||||||
|
_tokens = /* :: */[
|
||||||
|
/* CloseParen */1,
|
||||||
|
/* :: */[
|
||||||
|
/* Name */Block.__(2, [match$2[0]]),
|
||||||
|
tokens
|
||||||
|
]
|
||||||
|
];
|
||||||
|
_current = /* None */0;
|
||||||
|
_input = tail;
|
||||||
|
continue ;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_tokens = /* :: */[
|
||||||
|
/* CloseParen */1,
|
||||||
|
tokens
|
||||||
|
];
|
||||||
|
_current = /* None */0;
|
||||||
|
_input = tail;
|
||||||
|
continue ;
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (exit$2 === 3) {
|
||||||
|
if (current) {
|
||||||
|
var match$3 = current[0];
|
||||||
|
if (typeof match$3 === "number") {
|
||||||
|
exit$1 = 2;
|
||||||
|
} else if (match$3.tag === 1) {
|
||||||
|
_current = /* Some */[/* String */Block.__(1, [match$3[0] + $$String.make(1, head)])];
|
||||||
|
_input = tail;
|
||||||
|
continue ;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
exit$1 = 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
exit$1 = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (exit$1 === 2) {
|
||||||
|
if (head >= 32) {
|
||||||
|
if (head < 58) {
|
||||||
|
if (head >= 33) {
|
||||||
|
if (head >= 48) {
|
||||||
|
if (current) {
|
||||||
|
var match$4 = current[0];
|
||||||
|
if (typeof match$4 === "number") {
|
||||||
|
return List.rev(tokens);
|
||||||
|
} else if (match$4.tag) {
|
||||||
|
return List.rev(tokens);
|
||||||
|
} else {
|
||||||
|
_current = /* Some */[/* Number */Block.__(0, [match$4[0] + $$String.make(1, head)])];
|
||||||
|
_input = tail;
|
||||||
|
continue ;
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_current = /* Some */[/* Number */Block.__(0, [$$String.make(1, head)])];
|
||||||
|
_input = tail;
|
||||||
|
continue ;
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return List.rev(tokens);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
exit = 1;
|
||||||
|
}
|
||||||
|
} else if (head > 122 || head < 97) {
|
||||||
|
return List.rev(tokens);
|
||||||
|
} else if (current) {
|
||||||
|
var match$5 = current[0];
|
||||||
|
if (typeof match$5 === "number") {
|
||||||
|
return List.rev(tokens);
|
||||||
|
} else if (match$5.tag === 2) {
|
||||||
|
_current = /* Some */[/* Name */Block.__(2, [match$5[0] + $$String.make(1, head)])];
|
||||||
|
_input = tail;
|
||||||
|
continue ;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return List.rev(tokens);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_current = /* Some */[/* Name */Block.__(2, [$$String.make(1, head)])];
|
||||||
|
_input = tail;
|
||||||
|
continue ;
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (head >= 11) {
|
||||||
|
if (head !== 13) {
|
||||||
|
return List.rev(tokens);
|
||||||
|
} else {
|
||||||
|
exit = 1;
|
||||||
|
}
|
||||||
|
} else if (head >= 9) {
|
||||||
|
exit = 1;
|
||||||
|
} else {
|
||||||
|
return List.rev(tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (exit === 1) {
|
||||||
|
if (current) {
|
||||||
|
return List.rev(tokens);
|
||||||
|
} else {
|
||||||
|
_current = /* None */0;
|
||||||
|
_input = tail;
|
||||||
|
continue ;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return List.rev(tokens);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(Js_primitive.undefined_to_opt(JSON.stringify(tokenizer("(add 2 (subtract 4 2))"))));
|
||||||
|
|
||||||
|
var machine = /* record */[
|
||||||
|
/* current : None */0,
|
||||||
|
/* parsed : [] */0
|
||||||
|
];
|
||||||
|
|
||||||
|
exports.machine = machine;
|
||||||
|
exports.explode = explode;
|
||||||
|
exports.tokenizer = tokenizer;
|
||||||
|
/* Not a pure module */
|
59
src/compiler.re
Executable file
59
src/compiler.re
Executable file
@ -0,0 +1,59 @@
|
|||||||
|
type token =
|
||||||
|
| OpenParen
|
||||||
|
| CloseParen
|
||||||
|
| Number string
|
||||||
|
| String string
|
||||||
|
| Name string;
|
||||||
|
|
||||||
|
type tokenMachine = {
|
||||||
|
current: option token,
|
||||||
|
parsed: list token
|
||||||
|
};
|
||||||
|
|
||||||
|
let machine = {current: None, parsed: []};
|
||||||
|
|
||||||
|
let explode s => {
|
||||||
|
let rec exp i l =>
|
||||||
|
if (i < 0) {
|
||||||
|
l
|
||||||
|
} else {
|
||||||
|
exp (i - 1) [s.[i], ...l]
|
||||||
|
};
|
||||||
|
exp (String.length s - 1) []
|
||||||
|
};
|
||||||
|
|
||||||
|
let tokenizer input => {
|
||||||
|
let rec tok input current tokens =>
|
||||||
|
switch input {
|
||||||
|
| [] => List.rev tokens
|
||||||
|
| _ =>
|
||||||
|
let head = List.hd input;
|
||||||
|
let tail = List.tl input;
|
||||||
|
let next = tok tail;
|
||||||
|
switch (head, current, tokens) {
|
||||||
|
/* State: None */
|
||||||
|
| ('(', None, t) => next None [OpenParen, ...t]
|
||||||
|
| (')', None, t) => next None [CloseParen, ...t]
|
||||||
|
| (' ' | '\t' | '\r' | '\n', None, t) => next None t
|
||||||
|
| ('"', None, t) => next (Some (String "")) t
|
||||||
|
| ('0'..'9' as i, None, t) => next (Some (Number (String.make 1 i))) t
|
||||||
|
| ('a'..'z' as i, None, t) => next (Some (Name (String.make 1 i))) t
|
||||||
|
/* State: String */
|
||||||
|
| ('"', Some (String c), t) => next None [String c, ...t] /* TODO allow escaped double quotes :) */
|
||||||
|
| (i, Some (String c), t) => next (Some (String (c ^ String.make 1 i))) t
|
||||||
|
/* State: Number */
|
||||||
|
| ('0'..'9' as i, Some (Number c), t) => next (Some (Number (c ^ String.make 1 i))) t
|
||||||
|
| (')', Some (Number c), t) => next None [CloseParen, Number c, ...t]
|
||||||
|
| (' ', Some (Number c), t) => next None [Number c, ...t]
|
||||||
|
/* State: Name */
|
||||||
|
| ('a'..'z' as i, Some (Name c), t) => next (Some (Name (c ^ String.make 1 i))) t
|
||||||
|
| (')', Some (Name c), t) => next None [CloseParen, Name c, ...t]
|
||||||
|
| (' ', Some (Name c), t) => next None [Name c, ...t]
|
||||||
|
/* Errors */
|
||||||
|
| (_, _, t) => List.rev t /* TODO: handle errors */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
tok (explode input) machine.current machine.parsed
|
||||||
|
};
|
||||||
|
|
||||||
|
Js.log @@ Js.Json.stringifyAny (tokenizer "(add 2 (subtract 4 2))");
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user