From 4e7b684b0d2d0f1ea3ac5cf795f2f9e978033027 Mon Sep 17 00:00:00 2001 From: Sander Hautvast Date: Fri, 24 Jan 2020 12:48:51 +0100 Subject: [PATCH] completed main, added the scanner and token stubs --- src/main.rs | 17 +++++++++++-- src/scanner.rs | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/tokens.rs | 37 ++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 src/scanner.rs create mode 100644 src/tokens.rs diff --git a/src/main.rs b/src/main.rs index 3137064..7a868c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,9 @@ use std::fs::File; use std::io::{self, BufRead, Read, Write}; use std::process; +mod scanner; +mod tokens; + /// main /// no arguments: run interactively /// 1 argument: run the script file specified @@ -71,6 +74,16 @@ fn run_prompt() { } /// start interpreting and running the script -fn run(_source: String) -> Result<&'static str, &'static str> { - Ok("") +fn run(source: String) -> Result<&'static str, &'static str> { + return match scanner::scan_tokens(source.as_str()) { + Ok(tokens) => { + for token in tokens { + println!("{:?}", token); + } + Ok("Ok") + } + Err(code) => { + Err(code) + } + }; } \ No newline at end of file diff --git a/src/scanner.rs b/src/scanner.rs new file mode 100644 index 0000000..5027994 --- /dev/null +++ b/src/scanner.rs @@ -0,0 +1,65 @@ +use crate::tokens::{Token, TokenType}; +use crate::tokens::TokenType::*; + +/// public function for scanning lox source +/// outputs a Vector of Tokens +pub fn scan_tokens(source: &str) -> Result, &'static str> { + let mut scanner = Scanner::new(source); + + while !scanner.is_at_end() { + scanner.start = scanner.current; + scanner.scan_token() + } + + scanner.tokens.push(Token { + token_type: EOF, + lexeme: "lexeme", + literal: Box::new(""), + line: scanner.line, + }); + + if scanner.error_occured { + Err("Error occurred") + } else { + Ok(scanner.tokens) + } +} + +///struct used internally to keep state while scanning +struct Scanner<'a> { + // the source to scan + source: &'a str, + + // the tokens that will be the output of the scan function + tokens: Vec>, + + // start of unscanned source (updated after part of the source was scanned) + start: usize, + + // current character index while scanning + current: usize, + + // flag indicating compilation error + error_occured: bool, + + // current line (mainly used to report the line after a compilation error occurred) + line: usize, +} + +impl Scanner<'_> { + /// create Scanner struct using the source + fn new(source: &str) -> Scanner { + Scanner { tokens: Vec::new(), source, start: 0, current: 0, line: 1, error_occured: false } + } + + ///scans the source, character by character + fn scan_token(&mut self) {} + + /// adds a token of the given type + fn add_token(&mut self, token_type: TokenType) {} + + /// returns true iff the end of the source has been reached + fn is_at_end(&self) -> bool { + true + } +} diff --git a/src/tokens.rs b/src/tokens.rs new file mode 100644 index 0000000..dbeced7 --- /dev/null +++ b/src/tokens.rs @@ -0,0 +1,37 @@ +use std::any::Any; +use std::fmt; + +/// struct that contains a single token +pub struct Token<'a> { + // the type + pub lexeme: &'a str, + + // the actual part of the code that resulted in this token + pub literal: Box, + + // numeric (ie 1,2, 1.0 etc) and alphanumeric (any quoted text) values + pub line: usize, + + // the line that contains the code for this token instance + pub token_type: TokenType, +} + +impl fmt::Debug for Token<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let lit = match self.literal.downcast_ref::() { + Some(as_string) => { + as_string.to_string() + } + None => { + format!("{:?}", self.literal) + } + }; + + write!(f, "Token [ type: {:?}, lexeme: {}, literal: {}, line: {} ]", self.token_type, self.lexeme, lit, self.line) + } +} + +#[derive(Debug, Clone, Copy)] +pub enum TokenType { + EOF +} \ No newline at end of file