This commit is contained in:
mii
2021-09-15 08:44:12 +09:00
parent ab1a6ddcd2
commit d68d03289a
12 changed files with 1207 additions and 0 deletions

16
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,16 @@
{
// IntelliSense を使用して利用可能な属性を学べます。
// 既存の属性の説明をホバーして表示します。
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug",
"program": "${workspaceFolder}/<your program>",
"args": [],
"cwd": "${workspaceFolder}"
}
]
}

55
Cargo.lock generated Normal file
View File

@ -0,0 +1,55 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "getrandom"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "gpsl"
version = "0.1.0"
dependencies = [
"uuid",
]
[[package]]
name = "libc"
version = "0.2.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
[[package]]
name = "serde"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
[[package]]
name = "uuid"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
"getrandom",
"serde",
]
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"

8
Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "gpsl"
version = "0.1.0"
authors = ["mii"]
edition = "2018"
[dependencies]
uuid = { version = "0.8.1", features = ["serde", "v4"] }

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 mii8080
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

415
src/gpsl.rs Normal file
View File

@ -0,0 +1,415 @@
use crate::node::*;
use crate::parser::*;
use crate::source::Source;
use crate::tokenizer::*;
use crate::variable::*;
use std::collections::HashMap;
use std::string::*;
use uuid::Uuid;
pub struct GPSL {
pub source: Source,
pub l_vars: HashMap<String, LocalVariable>,
pub assembly: String,
pub offset_size: usize,
}
pub struct LocalVariable {
pub name: String,
pub value: Variable,
pub status: VariableStatus,
}
pub struct VariableStatus {
pub initialized: bool,
}
impl VariableStatus {
pub fn default() -> VariableStatus {
VariableStatus { initialized: false }
}
}
impl GPSL {
pub fn new(source: Source) -> GPSL {
GPSL {
source,
l_vars: HashMap::new(),
assembly: String::from(""),
offset_size: 0,
}
}
pub fn extract_number(node: Variable) -> Result<usize, String> {
match node {
Variable::Number { value } => {
Ok(value)
},
_ => {
Err(String::from("Not a number"))
}
}
}
pub fn evaluate(&mut self, node: Box<Node>) -> Result<Option<Variable>, String> {
match *node {
Node::Text { value } => {
Ok(Some(Variable::Text {
value
}))
}
Node::Number { value } => {
Ok(Some(Variable::Number {
value
}))
}
Node::Operator { kind, lhs, rhs } => {
if kind == NodeKind::ASSIGN {
let rhs = self.evaluate(rhs);
if let Ok(Some(rhs)) = rhs {
match *(lhs.clone()) {
Node::Lvar { value } => {
self.l_vars.get_mut(&value).unwrap().value = rhs;
self.l_vars.get_mut(&value).unwrap().status.initialized = true
}
_ => {}
}
}
return Ok(None);
}
let lhs = self.evaluate(lhs).expect("Cannot evaluate lhs.");
let rhs = self.evaluate(rhs).expect("Cannot evaluate rhs.");
if let Some(lhs) = lhs {
if let Some(rhs) = rhs {
match kind {
NodeKind::ADD => {
match GPSL::extract_number(lhs) {
Ok(lhs) => {
match GPSL::extract_number(rhs) {
Ok(rhs) => {
Ok(Some(Variable::Number {
value: lhs + rhs
}))
}
Err(err) => { Err(err) }
}
}
Err(err) => { Err(err) }
}
},
NodeKind::DIV => {
match GPSL::extract_number(lhs) {
Ok(lhs) => {
match GPSL::extract_number(rhs) {
Ok(rhs) => {
Ok(Some(Variable::Number {
value: lhs / rhs
}))
}
Err(err) => { Err(err) }
}
}
Err(err) => { Err(err) }
}
},
NodeKind::MUL => {
match GPSL::extract_number(lhs) {
Ok(lhs) => {
match GPSL::extract_number(rhs) {
Ok(rhs) => {
Ok(Some(Variable::Number {
value: lhs * rhs
}))
}
Err(err) => { Err(err) }
}
}
Err(err) => { Err(err) }
}
},
NodeKind::SUB => {
match GPSL::extract_number(lhs) {
Ok(lhs) => {
match GPSL::extract_number(rhs) {
Ok(rhs) => {
Ok(Some(Variable::Number {
value: lhs - rhs
}))
}
Err(err) => { Err(err) }
}
}
Err(err) => { Err(err) }
}
},
NodeKind::EQ => {
if lhs == rhs {
Ok(Some(Variable::Number {
value: 1
}))
} else {
Ok(Some(Variable::Number {
value: 0
}))
}
},
NodeKind::NE => {
if lhs != rhs {
Ok(Some(Variable::Number {
value: 1
}))
} else {
Ok(Some(Variable::Number {
value: 0
}))
}
},
NodeKind::LT => {
match GPSL::extract_number(lhs) {
Ok(lhs) => {
match GPSL::extract_number(rhs) {
Ok(rhs) => {
if lhs < rhs {
Ok(Some(Variable::Number {
value: 1
}))
} else {
Ok(Some(Variable::Number {
value: 0
}))
}
}
Err(err) => { Err(err) }
}
}
Err(err) => { Err(err) }
}
},
NodeKind::LE => {
match GPSL::extract_number(lhs) {
Ok(lhs) => {
match GPSL::extract_number(rhs) {
Ok(rhs) => {
if lhs <= rhs {
Ok(Some(Variable::Number {
value: 1
}))
} else {
Ok(Some(Variable::Number {
value: 0
}))
}
}
Err(err) => { Err(err) }
}
}
Err(err) => { Err(err) }
}
},
_ => Ok(None)
}
} else {
Err(String::from("RHS Variable is null."))
}
} else {
Err(String::from("LHS Variable is null."))
}
}
Node::Lvar { value } => {
return Ok(Some(self.l_vars.get(&value).unwrap().value.clone()));
}
Node::Return { lhs } => {
if let Ok(Some(lhs)) = self.evaluate(lhs) {
return Ok(Some(Variable::Return {
value: Box::new(lhs)
}));
} else {
return Err(String::from("Cannot evaluate LHS."));
}
}
Node::If {
condition,
stmt,
else_stmt,
} => {
if let Ok(Some(condition)) = self.evaluate(condition) {
if match condition {
Variable::Number { value } => value == 1,
_ => false
} {
if let Ok(Some(res)) = self.evaluate(stmt) {
match res.clone() {
Variable::Return { value } => {
return Ok(Some(res));
}
_ => {}
}
}
} else {
match else_stmt {
Some(else_stmt) => {
if let Ok(Some(res)) = self.evaluate(else_stmt) {
match res.clone() {
Variable::Return { value } => {
return Ok(Some(res));
}
_ => {}
}
}
}
None => {}
}
}
}
return Ok(None);
}
Node::While { condition, stmt } => {
let mut cond = if let Some(condition) = self.evaluate(condition.clone())? {
condition
} else {
Variable::Number {
value: 0
}
};
while match cond {
Variable::Number { value } => value == 1,
_ => false
} {
self.evaluate(stmt.clone())?;
cond = if let Some(condition) = self.evaluate(condition.clone())? {
condition
} else {
Variable::Number {
value: 0
}
};
}
return Ok(None);
}
Node::For {
init,
condition,
update,
stmt,
} => {
match init {
Some(init) => {self.evaluate(init)?;},
None => {}
}
let mut cond = match condition.clone() {
Some(condition) => {
if let Some(condition) = self.evaluate(condition)? {
condition
} else {
Variable::Number {
value: 0
}
}
},
None => {
Variable::Number {
value: 1
}
}
};
while match cond {
Variable::Number { value } => value == 1,
_ => false
} {
self.evaluate(stmt.clone())?;
match update.clone() {
Some(update) => {self.evaluate(update)?;},
None => {}
}
cond = match condition.clone() {
Some(condition) => {
if let Some(condition) = self.evaluate(condition)? {
condition
} else {
Variable::Number {
value: 0
}
}
},
None => {
Variable::Number {
value: 1
}
}
};
}
return Ok(None);
}
Node::Block { stmts } => {
for stmt in stmts {
let ret = self.evaluate(stmt)?;
if let Some(ret) = ret {
match ret.clone() {
Variable::Return { value } => {
return Ok(Some(ret));
}
_ => {}
}
}
}
return Ok(None);
}
Node::Define { name, var_type } => {
let value = if var_type == "num" {
Variable::Number {
value: 0
}
} else {
return Err(format!("{}: 未知の型です。", var_type));
};
self.l_vars.insert(
name.clone(),
LocalVariable {
name,
value,
status: VariableStatus::default(),
},
);
return Ok(None);
}
}
}
pub fn run(&mut self) -> Result<Variable, String> {
let mut tokenizer = Tokenizer::new();
tokenizer.tokenize(&mut self.source)?;
let mut parser = Parser {
tokenizer: tokenizer.clone(),
local_vars: HashMap::new(),
};
let programs = parser.program()?;
for program in programs {
if let Ok(Some(res)) = self.evaluate(program) {
match res {
Variable::Return { value } => {
return Ok(*value);
}
_ => {}
}
}
}
Ok(Variable::None {})
}
}

7
src/lib.rs Normal file
View File

@ -0,0 +1,7 @@
pub mod node;
pub mod parser;
pub mod gpsl;
pub mod source;
pub mod token;
pub mod tokenizer;
pub mod variable;

69
src/node.rs Normal file
View File

@ -0,0 +1,69 @@
#[derive(Debug, PartialEq, Clone)]
pub enum NodeKind {
ASSIGN,
ADD,
SUB,
MUL,
DIV,
EQ, // ==
NE, // !=
LT, // <
LE, // <=
}
#[derive(Debug, Clone, PartialEq)]
pub enum Node {
Operator {
kind: NodeKind,
lhs: Box<Node>,
rhs: Box<Node>,
},
Number {
value: usize,
},
Text {
value: String,
},
Lvar {
value: String,
},
Return {
lhs: Box<Node>,
},
If {
condition: Box<Node>,
stmt: Box<Node>,
else_stmt: Option<Box<Node>>,
},
While {
condition: Box<Node>,
stmt: Box<Node>,
},
For {
init: Option<Box<Node>>,
condition: Option<Box<Node>>,
update: Option<Box<Node>>,
stmt: Box<Node>,
},
Block {
stmts: Vec<Box<Node>>,
},
Define {
name: String,
var_type: String,
},
}
impl Node {
pub fn new_node(kind: NodeKind, lhs: Box<Node>, rhs: Box<Node>) -> Box<Node> {
Box::new(Node::Operator { kind, lhs, rhs })
}
pub fn new_num_node(value: usize) -> Box<Node> {
Box::new(Node::Number { value })
}
pub fn new_lvar_node(value: String) -> Box<Node> {
Box::new(Node::Lvar { value })
}
}

263
src/parser.rs Normal file
View File

@ -0,0 +1,263 @@
use crate::node::*;
use crate::token::*;
use crate::tokenizer::*;
use std::collections::HashMap;
#[derive(Clone)]
pub struct Parser {
pub tokenizer: Tokenizer,
pub local_vars: HashMap<String, usize>,
}
impl Parser {
pub fn program(&mut self) -> Result<Vec<Box<Node>>, String> {
let mut nodes: Vec<Box<Node>> = vec![];
loop {
if self.tokenizer.current_token().kind != TokenKind::EOF {
nodes.push(self.stmt()?);
} else {
return Ok(nodes);
}
}
}
pub fn stmt(&mut self) -> Result<Box<Node>, String> {
if self
.tokenizer
.consume_kind_str(TokenKind::IDENT, String::from("let"))
{
let ident = self.tokenizer.current_token().clone();
self.tokenizer.expect_kind(TokenKind::IDENT)?;
self.tokenizer.expect(String::from(":"))?;
let var_type = self.tokenizer.current_token().clone();
self.tokenizer.expect_kind(TokenKind::IDENT)?;
self.tokenizer.expect(String::from(";"))?;
return Ok(Box::new(Node::Define {
name: ident.str,
var_type: var_type.str,
}));
}
if self
.tokenizer
.consume_kind_str(TokenKind::RESERVED, String::from("{"))
{
let mut stmts: Vec<Box<Node>> = vec![];
loop {
if self
.tokenizer
.consume_kind_str(TokenKind::RESERVED, String::from("}"))
{
return Ok(Box::new(Node::Block { stmts }));
} else {
stmts.push(self.stmt()?);
}
}
}
if self.tokenizer.consume_kind(TokenKind::RETURN) {
let node = Node::Return { lhs: self.expr()? };
self.tokenizer.expect(String::from(";"))?;
return Ok(Box::new(node));
}
if self.tokenizer.current_token().kind == TokenKind::CONTROL {
match &*self.tokenizer.current_token().str {
"if" => {
self.tokenizer.cursor += 1;
self.tokenizer.expect(String::from("("))?;
let condition = self.expr()?;
self.tokenizer.expect(String::from(")"))?;
let stmt = self.stmt()?;
let mut else_stmt: Option<Box<Node>> = None;
if self
.tokenizer
.consume_kind_str(TokenKind::CONTROL, String::from("else"))
{
else_stmt = Some(self.stmt()?);
}
return Ok(Box::new(Node::If {
condition,
stmt,
else_stmt,
}));
}
"while" => {
self.tokenizer.cursor += 1;
self.tokenizer.expect(String::from("("))?;
let condition = self.expr()?;
self.tokenizer.expect(String::from(")"))?;
let stmt = self.stmt()?;
return Ok(Box::new(Node::While { condition, stmt }));
}
"for" => {
self.tokenizer.cursor += 1;
self.tokenizer.expect(String::from("("))?;
let init: Option<Box<Node>> =
if self.tokenizer.current_token().str != String::from(";") {
Some(self.expr()?)
} else {
None
};
self.tokenizer.expect(String::from(";"))?;
let condition: Option<Box<Node>> =
if self.tokenizer.current_token().str != String::from(";") {
Some(self.expr()?)
} else {
None
};
self.tokenizer.expect(String::from(";"))?;
let update: Option<Box<Node>> =
if self.tokenizer.current_token().str != String::from(")") {
Some(self.expr()?)
} else {
None
};
self.tokenizer.expect(String::from(")"))?;
let stmt = self.stmt()?;
return Ok(Box::new(Node::For {
init,
condition,
update,
stmt,
}));
}
_ => {}
}
}
let node = self.expr();
self.tokenizer.expect(String::from(";"))?;
return node;
}
pub fn expr(&mut self) -> Result<Box<Node>, String> {
Ok(self.assign()?)
}
pub fn assign(&mut self) -> Result<Box<Node>, String> {
let mut node = self.equality()?;
if self.tokenizer.consume(String::from("=")) {
node = Node::new_node(NodeKind::ASSIGN, node, self.assign()?);
}
Ok(node)
}
pub fn equality(&mut self) -> Result<Box<Node>, String> {
let mut node = self.relational()?;
loop {
if self.tokenizer.consume(String::from("==")) {
node = Node::new_node(NodeKind::EQ, node, self.relational()?);
} else if self.tokenizer.consume(String::from("!=")) {
node = Node::new_node(NodeKind::NE, node, self.relational()?);
} else {
return Ok(node);
}
}
}
pub fn relational(&mut self) -> Result<Box<Node>, String> {
let mut node = self.add()?;
loop {
if self.tokenizer.consume(String::from("<=")) {
node = Node::new_node(NodeKind::LE, node, self.add()?);
} else if self.tokenizer.consume(String::from("<")) {
node = Node::new_node(NodeKind::LT, node, self.add()?);
} else if self.tokenizer.consume(String::from(">=")) {
node = Node::new_node(NodeKind::LE, self.add()?, node);
} else if self.tokenizer.consume(String::from(">")) {
node = Node::new_node(NodeKind::LT, self.add()?, node);
} else {
return Ok(node);
}
}
}
pub fn add(&mut self) -> Result<Box<Node>, String> {
let mut node = self.mul()?;
loop {
if self.tokenizer.consume(String::from("+")) {
node = Node::new_node(NodeKind::ADD, node, self.mul()?);
} else if self.tokenizer.consume(String::from("-")) {
node = Node::new_node(NodeKind::SUB, node, self.mul()?);
} else if self.tokenizer.consume(String::from("+=")) {
node = Node::new_node(
NodeKind::ASSIGN,
Box::new((*node).clone()),
Node::new_node(NodeKind::ADD, node, self.mul()?),
);
} else if self.tokenizer.consume(String::from("-=")) {
node = Node::new_node(
NodeKind::ASSIGN,
Box::new((*node).clone()),
Node::new_node(NodeKind::SUB, node, self.mul()?),
);
} else {
return Ok(node);
}
}
}
pub fn mul(&mut self) -> Result<Box<Node>, String> {
let mut node = self.unary()?;
loop {
if self.tokenizer.consume(String::from("*")) {
node = Node::new_node(NodeKind::MUL, node, self.unary()?);
} else if self.tokenizer.consume(String::from("/")) {
node = Node::new_node(NodeKind::DIV, node, self.unary()?);
} else if self.tokenizer.consume(String::from("*=")) {
node = Node::new_node(
NodeKind::ASSIGN,
Box::new((*node).clone()),
Node::new_node(NodeKind::MUL, node, self.unary()?),
);
} else if self.tokenizer.consume(String::from("/=")) {
node = Node::new_node(
NodeKind::ASSIGN,
Box::new((*node).clone()),
Node::new_node(NodeKind::DIV, node, self.unary()?),
);
} else {
return Ok(node);
}
}
}
pub fn primary(&mut self) -> Result<Box<Node>, String> {
if self.tokenizer.consume(String::from("(")) {
let node = self.expr()?;
self.tokenizer.expect(String::from(")"))?;
return Ok(node);
}
if self.tokenizer.current_token().kind == TokenKind::IDENT {
let node = self.tokenizer.expect_ident()?;
return Ok(Node::new_lvar_node(node.clone()));
}
return Ok(Node::new_num_node(self.tokenizer.expect_number()?));
}
pub fn unary(&mut self) -> Result<Box<Node>, String> {
if self.tokenizer.consume(String::from("+")) {
return Ok(self.primary()?);
}
if self.tokenizer.consume(String::from("-")) {
return Ok(Node::new_node(
NodeKind::SUB,
Node::new_num_node(0),
self.primary()?,
));
}
return Ok(self.primary()?);
}
}

91
src/source.rs Normal file
View File

@ -0,0 +1,91 @@
#[derive(Clone)]
pub struct Source {
pub src: Vec<char>,
pub pos: usize,
}
impl Source {
pub fn get_char(&mut self, check: impl Fn(char) -> bool) -> Result<char, String> {
match self.get_next() {
Ok(c) => {
if check(c) {
Ok(c)
} else {
self.pos -= 1;
Err(String::from("Not found."))
}
}
Err(text) => Err(text),
}
}
pub fn get_string(&mut self, string: String) -> Result<String, String> {
let first_pos = self.pos;
for i in 0..string.chars().count() {
if self.has_next() {
match self.get_next() {
Ok(c) => {
if c == string.chars().nth(i).unwrap() {
continue;
} else {
self.pos = first_pos;
return Err(String::from(""));
}
}
Err(_) => {}
}
} else {
self.pos = first_pos;
return Err(String::from(""));
}
}
Ok(string)
}
pub fn get_chars(&mut self, check: impl Fn(char) -> bool) -> Result<String, String> {
let mut buffer = String::from("");
while self.has_next() {
match self.get_next() {
Ok(c) => {
if check(c) {
buffer += &c.to_string();
} else {
self.pos -= 1;
break;
}
}
Err(_) => {
break;
}
}
}
if buffer == "" {
Err(String::from("Not found."))
} else {
Ok(buffer)
}
}
pub fn get_next(&mut self) -> Result<char, String> {
self.pos += 1;
if self.src.len() > self.pos - 1 {
Ok(self.src[self.pos - 1])
} else {
Err(String::from("EOF"))
}
}
pub fn new(src: String) -> Source {
Source {
src: src.chars().collect(),
pos: 0,
}
}
pub fn has_next(&self) -> bool {
self.src.len() > self.pos
}
}

16
src/token.rs Normal file
View File

@ -0,0 +1,16 @@
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum TokenKind {
CONTROL,
RETURN,
RESERVED,
IDENT,
NUMBER,
EOF,
}
#[derive(Clone, Debug)]
pub struct Token {
pub kind: TokenKind,
pub num: usize,
pub str: String,
}

232
src/tokenizer.rs Normal file
View File

@ -0,0 +1,232 @@
use crate::source::*;
use crate::token::*;
#[derive(Clone)]
pub struct Tokenizer {
pub tokens: Vec<Token>,
pub cursor: usize,
}
impl Tokenizer {
pub fn current_token(&mut self) -> &mut Token {
&mut self.tokens[self.cursor]
}
pub fn consume(&mut self, op: String) -> bool {
return if self.current_token().kind != TokenKind::RESERVED || self.current_token().str != op
{
false
} else {
self.cursor += 1;
true
};
}
pub fn consume_kind(&mut self, kind: TokenKind) -> bool {
return if self.current_token().kind != kind {
false
} else {
self.cursor += 1;
true
};
}
pub fn consume_kind_str(&mut self, kind: TokenKind, string: String) -> bool {
return if self.current_token().kind == kind && self.current_token().str == string {
self.cursor += 1;
true
} else {
false
};
}
pub fn expect(&mut self, op: String) -> Result<(), String> {
if self.current_token().str != op {
return Err(format!("Unexpected type : {}", op));
}
self.cursor += 1;
Ok(())
}
pub fn expect_kind(&mut self, kind: TokenKind) -> Result<(), String> {
if self.current_token().kind != kind {
return Err(format!("Unexpected token: {:?}", self.current_token().kind));
}
self.cursor += 1;
Ok(())
}
pub fn expect_ident(&mut self) -> Result<String, String> {
if self.current_token().kind != TokenKind::IDENT {
return Err(format!(
"Unexpected type : {:?}",
self.current_token().kind
));
}
let val = self.current_token().str.clone();
self.cursor += 1;
Ok(val.to_string())
}
pub fn expect_number(&mut self) -> Result<usize, String> {
let kind = self.current_token().kind;
if kind != TokenKind::NUMBER {
return Err(format!("Unexpected type : {:?}", kind));
}
let val = self.current_token().num;
self.cursor += 1;
Ok(val)
}
pub fn new() -> Tokenizer {
Tokenizer {
cursor: 0,
tokens: vec![],
}
}
pub fn create_reserved(op: String) -> Token {
Token {
kind: TokenKind::RESERVED,
str: op,
num: 0,
}
}
pub fn create_number(num: usize) -> Token {
Token {
kind: TokenKind::NUMBER,
num: num,
str: String::default(),
}
}
pub fn tokenize(&mut self, source: &mut Source) -> Result<Vec<Token>, String> {
let reserved: Vec<String> = vec![
String::from("+="),
String::from("-="),
String::from("*="),
String::from("/="),
String::from("+"),
String::from("-"),
String::from("*"),
String::from("/"),
String::from("&&"),
String::from("&"),
String::from("{"),
String::from("}"),
String::from("("),
String::from(")"),
String::from("=="),
String::from("!="),
String::from(">="),
String::from("<="),
String::from("<"),
String::from(">"),
String::from("="),
String::from(";"),
String::from(":"),
];
let controls: Vec<String> = vec![
String::from("for"),
String::from("while"),
String::from("if"),
String::from("else"),
];
while source.has_next() {
match source.get_char(is_whitespace) {
Ok(_) => {
continue;
}
Err(_) => {}
}
match contains_list_chars(source, reserved.clone()) {
Ok(op) => {
self.tokens
.push(Tokenizer::create_reserved(String::from(op)));
continue;
}
Err(_) => {}
}
match source.get_chars(is_digit) {
Ok(num) => {
self.tokens
.push(Tokenizer::create_number(num.parse().unwrap()));
continue;
}
Err(_) => {}
}
match source.get_chars(or(is_ascii_lowercase, or(is_digit, is('_')))) {
Ok(c) => {
if c == String::from("return") {
self.tokens.push(Token {
kind: TokenKind::RETURN,
str: String::default(),
num: 0,
});
continue;
}
if controls.contains(&c) {
self.tokens.push(Token {
kind: TokenKind::CONTROL,
str: c,
num: 0,
});
continue;
}
self.tokens.push(Token {
kind: TokenKind::IDENT,
str: c,
num: 0,
});
continue;
}
Err(_) => {}
}
return Err(String::from("Failed to tokenize"));
}
self.tokens.push(Token {
kind: TokenKind::EOF,
str: String::default(),
num: 0,
});
Ok(self.tokens.clone())
}
}
fn contains_list_chars(source: &mut Source, list: Vec<String>) -> Result<String, String> {
for target in list {
match source.get_string(target) {
Ok(string) => {
return Ok(string);
}
Err(_) => {}
}
}
return Err(String::from(""));
}
fn or(f: impl Fn(char) -> bool, g: impl Fn(char) -> bool) -> impl Fn(char) -> bool {
move |c| f(c) || g(c)
}
fn is(ch: char) -> impl Fn(char) -> bool {
move |c| c == ch
}
fn is_whitespace(c: char) -> bool {
c.is_whitespace()
}
fn is_digit(c: char) -> bool {
c.is_digit(10)
}
fn is_ascii_lowercase(c: char) -> bool {
c.is_ascii_lowercase()
}

14
src/variable.rs Normal file
View File

@ -0,0 +1,14 @@
#[derive(Clone, PartialEq, Debug)]
pub enum Variable {
Number {
value: usize,
},
Text {
value: String,
},
Return {
value: Box<Variable>
},
None {}
}