mirror of
https://github.com/mii443/encrypt.git
synced 2025-08-22 15:05:33 +00:00
init
This commit is contained in:
16
.vscode/launch.json
vendored
Normal file
16
.vscode/launch.json
vendored
Normal 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
55
Cargo.lock
generated
Normal 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
8
Cargo.toml
Normal 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
21
LICENSE
Normal 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
415
src/gpsl.rs
Normal 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
7
src/lib.rs
Normal 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
69
src/node.rs
Normal 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
263
src/parser.rs
Normal 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
91
src/source.rs
Normal 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
16
src/token.rs
Normal 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
232
src/tokenizer.rs
Normal 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
14
src/variable.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
pub enum Variable {
|
||||||
|
Number {
|
||||||
|
value: usize,
|
||||||
|
},
|
||||||
|
Text {
|
||||||
|
value: String,
|
||||||
|
},
|
||||||
|
Return {
|
||||||
|
value: Box<Variable>
|
||||||
|
},
|
||||||
|
None {}
|
||||||
|
}
|
Reference in New Issue
Block a user