Scanning on Demand 16
This commit is contained in:
parent
aba643a88e
commit
8fb449825d
6 changed files with 209 additions and 32 deletions
9
src/clox/compiler.d
Normal file
9
src/clox/compiler.d
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
module clox.compiler;
|
||||||
|
|
||||||
|
import std.stdio;
|
||||||
|
|
||||||
|
import clox.scanner;
|
||||||
|
|
||||||
|
void compile(string source) @nogc nothrow {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,38 +1,46 @@
|
||||||
module clox.main;
|
module clox.main;
|
||||||
|
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
|
import std.file;
|
||||||
|
|
||||||
import clox.chunk;
|
import clox.chunk;
|
||||||
import clox.dbg;
|
import clox.dbg;
|
||||||
import clox.vm;
|
import clox.vm;
|
||||||
|
|
||||||
int main(string[] argv){
|
extern(C) int isatty(int);
|
||||||
Chunk chunk;
|
|
||||||
|
|
||||||
ubyte constant = chunk.addConstant(1.2);
|
|
||||||
chunk.write(OpCode.Constant);
|
|
||||||
chunk.write(constant);
|
|
||||||
|
|
||||||
constant = chunk.addConstant(3.4);
|
|
||||||
chunk.write(OpCode.Constant);
|
|
||||||
chunk.write(constant);
|
|
||||||
|
|
||||||
chunk.write(OpCode.Add);
|
|
||||||
|
|
||||||
constant = chunk.addConstant(5.6);
|
|
||||||
chunk.write(OpCode.Constant);
|
|
||||||
chunk.write(constant);
|
|
||||||
|
|
||||||
chunk.write(OpCode.Divide);
|
|
||||||
|
|
||||||
chunk.write(OpCode.Negate);
|
|
||||||
|
|
||||||
chunk.write(OpCode.Return);
|
|
||||||
|
|
||||||
VM vm = VM(0);
|
|
||||||
vm.interpret(&chunk);
|
|
||||||
|
|
||||||
|
|
||||||
|
struct Lox{
|
||||||
|
VM vm;
|
||||||
|
this(int _){
|
||||||
|
vm = VM(0);
|
||||||
|
}
|
||||||
|
int runFile(string path){
|
||||||
|
string source = path.readText();
|
||||||
|
VM.InterpretResult result = vm.interpret(source);
|
||||||
|
final switch(result){
|
||||||
|
case VM.InterpretResult.CompileError: return 65;
|
||||||
|
case VM.InterpretResult.RuntimeError: return 70;
|
||||||
|
case VM.InterpretResult.Ok: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int runPrompt(){
|
||||||
|
while(true){
|
||||||
|
write("> ");
|
||||||
|
string line = stdin.readln();
|
||||||
|
if(!line){
|
||||||
|
writeln();
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
vm.interpret(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(string[] argv){
|
||||||
|
Lox lox = Lox(0);
|
||||||
|
if(isatty(stdin.fileno))
|
||||||
|
return lox.runPrompt();
|
||||||
|
else
|
||||||
|
return lox.runFile("/dev/stdin");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
153
src/clox/scanner.d
Normal file
153
src/clox/scanner.d
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
module clox.scanner;
|
||||||
|
|
||||||
|
import std.stdio;
|
||||||
|
import std.ascii;
|
||||||
|
|
||||||
|
import common.util;
|
||||||
|
|
||||||
|
struct Token{
|
||||||
|
enum Type : ubyte {
|
||||||
|
LeftParen, RightParen, // Single-character tokens.
|
||||||
|
LeftBrace, RightBrace,
|
||||||
|
Comma, Dot, Minus, Plus,
|
||||||
|
Semicolon, Slash, Star,
|
||||||
|
Bang, BangEqual, // One or two character tokens.
|
||||||
|
Equal, EqualEqual,
|
||||||
|
Greater, GreaterEqual,
|
||||||
|
Less, LessEqual,
|
||||||
|
Identifier, String, Number, // Literals.
|
||||||
|
And, Class, Else, False, // Keywords.
|
||||||
|
For, Fun, If, Nil, Or,
|
||||||
|
Print, Return, Super, This,
|
||||||
|
True, Var, While,
|
||||||
|
Error, EOF // Special
|
||||||
|
}
|
||||||
|
Type type;
|
||||||
|
int line;
|
||||||
|
string lexeme;
|
||||||
|
static Token error(string msg) => Token(Token.Type.Error, 0, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Scanner{
|
||||||
|
string start;
|
||||||
|
string current;
|
||||||
|
int line = 1;
|
||||||
|
this(string source){
|
||||||
|
start = current = source;
|
||||||
|
}
|
||||||
|
bool isAtEnd() const => current.length == 0;
|
||||||
|
private char peek() const => current[0];
|
||||||
|
private char peekNext() const => current.length >= 2 ? current[1] : '\0';
|
||||||
|
private Token makeToken(Token.Type type) const{
|
||||||
|
Token token;
|
||||||
|
token.type = type;
|
||||||
|
token.lexeme = start[0 .. current.ptr - start.ptr];
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
private char advance(){
|
||||||
|
char c = current[0];
|
||||||
|
current = current[1 .. $];
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
private bool match(char needle){
|
||||||
|
if(isAtEnd || current[0] != needle)
|
||||||
|
return false;
|
||||||
|
current = current[1 .. $];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
private void skipWhitespace(){
|
||||||
|
while(!isAtEnd){
|
||||||
|
char c = peek();
|
||||||
|
if(!c)
|
||||||
|
return;
|
||||||
|
if(c == '/' && peekNext() == '/'){
|
||||||
|
while(!isAtEnd && peek() != '\n')
|
||||||
|
advance();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(!c.isWhite)
|
||||||
|
return;
|
||||||
|
if(c == '\n')
|
||||||
|
line++;
|
||||||
|
current = current[1 .. $];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private Token parseString(){
|
||||||
|
while(peek() != '"' && !isAtEnd){
|
||||||
|
if(peek() == '\n')
|
||||||
|
line++;
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
if(isAtEnd)
|
||||||
|
return Token.error("Unterminated string.");
|
||||||
|
advance();
|
||||||
|
return makeToken(Token.Type.String);
|
||||||
|
}
|
||||||
|
private Token parseNumber(){
|
||||||
|
while(peek().isDigit)
|
||||||
|
advance();
|
||||||
|
if(peek() == '.' && peekNext().isDigit){
|
||||||
|
advance();
|
||||||
|
while(peek().isDigit)
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
return makeToken(Token.Type.Number);
|
||||||
|
}
|
||||||
|
private Token parseIdentifier(){
|
||||||
|
while(peek().isAlphaNum_)
|
||||||
|
advance();
|
||||||
|
Token token = makeToken(Token.Type.Identifier);
|
||||||
|
switch(token.lexeme){
|
||||||
|
case "and": token.type = Token.Type.And; break;
|
||||||
|
case "class": token.type = Token.Type.Class; break;
|
||||||
|
case "else": token.type = Token.Type.Else; break;
|
||||||
|
case "if": token.type = Token.Type.If; break;
|
||||||
|
case "nil": token.type = Token.Type.Nil; break;
|
||||||
|
case "or": token.type = Token.Type.Or; break;
|
||||||
|
case "print": token.type = Token.Type.Print; break;
|
||||||
|
case "return": token.type = Token.Type.Return; break;
|
||||||
|
case "super": token.type = Token.Type.Super; break;
|
||||||
|
case "var": token.type = Token.Type.Var; break;
|
||||||
|
case "while": token.type = Token.Type.While; break;
|
||||||
|
case "false": token.type = Token.Type.False; break;
|
||||||
|
case "for": token.type = Token.Type.For; break;
|
||||||
|
case "fun": token.type = Token.Type.Fun; break;
|
||||||
|
case "this": token.type = Token.Type.This; break;
|
||||||
|
case "true": token.type = Token.Type.True; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
Token scan(){
|
||||||
|
skipWhitespace();
|
||||||
|
start = current;
|
||||||
|
if(isAtEnd)
|
||||||
|
return Token(Token.Type.EOF);
|
||||||
|
char c = advance();
|
||||||
|
if(c.isAlpha_)
|
||||||
|
return parseIdentifier();
|
||||||
|
switch(c){
|
||||||
|
case '(': return makeToken(Token.Type.LeftParen);
|
||||||
|
case ')': return makeToken(Token.Type.RightParen);
|
||||||
|
case '{': return makeToken(Token.Type.LeftBrace);
|
||||||
|
case '}': return makeToken(Token.Type.RightBrace);
|
||||||
|
case ';': return makeToken(Token.Type.Semicolon);
|
||||||
|
case ',': return makeToken(Token.Type.Comma);
|
||||||
|
case '.': return makeToken(Token.Type.Dot);
|
||||||
|
case '-': return makeToken(Token.Type.Minus);
|
||||||
|
case '+': return makeToken(Token.Type.Plus);
|
||||||
|
case '/': return makeToken(Token.Type.Slash);
|
||||||
|
case '*': return makeToken(Token.Type.Star);
|
||||||
|
case '!': return makeToken(match('=') ? Token.Type.BangEqual : Token.Type.Bang);
|
||||||
|
case '=': return makeToken(match('=') ? Token.Type.EqualEqual : Token.Type.Equal);
|
||||||
|
case '<': return makeToken(match('=') ? Token.Type.LessEqual : Token.Type.Less);
|
||||||
|
case '>': return makeToken(match('=') ? Token.Type.GreaterEqual : Token.Type.Greater);
|
||||||
|
case '"': return parseString();
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
if(c.isDigit)
|
||||||
|
return parseNumber();
|
||||||
|
return Token.error("Unexpected character '" ~ c ~ "'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -6,6 +6,7 @@ import clox.chunk;
|
||||||
import clox.value;
|
import clox.value;
|
||||||
import clox.dbg;
|
import clox.dbg;
|
||||||
import clox.util;
|
import clox.util;
|
||||||
|
import clox.compiler;
|
||||||
|
|
||||||
enum stackMax = 256;
|
enum stackMax = 256;
|
||||||
|
|
||||||
|
|
@ -13,10 +14,14 @@ struct VM{
|
||||||
const(ubyte)* ip;
|
const(ubyte)* ip;
|
||||||
Stack!(Value, stackMax) stack;
|
Stack!(Value, stackMax) stack;
|
||||||
Chunk* chunk;
|
Chunk* chunk;
|
||||||
enum InterpretResult{ Ok, CompileError, RunetimeError }
|
enum InterpretResult{ Ok, CompileError, RuntimeError }
|
||||||
this(int _) @nogc nothrow {
|
this(int _) @nogc nothrow {
|
||||||
stack = typeof(stack)(0);
|
stack = typeof(stack)(0);
|
||||||
}
|
}
|
||||||
|
InterpretResult interpret(string source) @nogc nothrow {
|
||||||
|
compile(source);
|
||||||
|
return InterpretResult.Ok;
|
||||||
|
}
|
||||||
InterpretResult interpret(Chunk* chunk) @nogc nothrow {
|
InterpretResult interpret(Chunk* chunk) @nogc nothrow {
|
||||||
this.chunk = chunk;
|
this.chunk = chunk;
|
||||||
ip = &chunk.code[0];
|
ip = &chunk.code[0];
|
||||||
|
|
|
||||||
|
|
@ -7,3 +7,7 @@ template defaultCtor(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import std.ascii : isAlpha, isAlphaNum;
|
||||||
|
bool isAlpha_(dchar c) => c.isAlpha || c == '_';
|
||||||
|
bool isAlphaNum_(dchar c) => c.isAlphaNum || c == '_';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,9 @@ import std.conv;
|
||||||
import jlox.token;
|
import jlox.token;
|
||||||
import jlox.tokentype;
|
import jlox.tokentype;
|
||||||
import jlox.main;
|
import jlox.main;
|
||||||
|
import common.util;
|
||||||
|
|
||||||
private bool isAlpha_(dchar c) => c.isAlpha || c == '_';
|
class Scanner{
|
||||||
private bool isAlphaNum_(dchar c) => c.isAlphaNum || c == '_';
|
|
||||||
|
|
||||||
class Scanner {
|
|
||||||
private string source;
|
private string source;
|
||||||
private Token[] tokens;
|
private Token[] tokens;
|
||||||
private uint start = 0;
|
private uint start = 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue