support for injected request args (path, query, headers)
This commit is contained in:
parent
42c431d5c7
commit
3142e59450
7 changed files with 76 additions and 47 deletions
|
|
@ -1,17 +1,13 @@
|
||||||
fn get():
|
fn get():
|
||||||
#path(/) -> list:
|
| path == "/" -> list:
|
||||||
service.get_all()
|
service.get_all()
|
||||||
|
| path == "/{uuid}" -> Customer?:
|
||||||
#path(/id/{uuid}) -> Customer?:
|
|
||||||
service.get(uuid)?
|
service.get(uuid)?
|
||||||
|
| path == "/" && query.firstname -> Customer?:
|
||||||
#path(?firstname={fname} | lastname={lname}) -> Customer?:
|
|
||||||
if name:
|
|
||||||
service.get_by_firstname(fname)?
|
service.get_by_firstname(fname)?
|
||||||
else if lastname:
|
| path == "/" && query.last_name -> Customer?
|
||||||
service.get_by_lastname(lname)?
|
service.get_by_lastname(lname)?
|
||||||
else:
|
| 404
|
||||||
404
|
|
||||||
|
|
||||||
fn post(customer: Customer):
|
fn post(customer: Customer):
|
||||||
service.add(customer)
|
service.add(customer)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
fn get() -> string:
|
fn get(path: string) -> string:
|
||||||
add("hello", "world")
|
add("hello", path)
|
||||||
|
|
||||||
fn add(a: string, b: string) -> string:
|
fn add(a: string, b: string) -> string:
|
||||||
a + " " + b
|
a + " " + b
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::ast_compiler::Expression::Variable;
|
||||||
use crate::errors::CompilerError::{
|
use crate::errors::CompilerError::{
|
||||||
self, Expected, IncompatibleTypes, ParseError, TooManyParameters, TypeError, UnexpectedIndent,
|
self, Expected, IncompatibleTypes, ParseError, TooManyParameters, TypeError, UnexpectedIndent,
|
||||||
UninitializedVariable,
|
UninitializedVariable,
|
||||||
|
|
@ -15,8 +16,11 @@ use crate::value::Value;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub fn compile(tokens: Vec<Token>) -> Result<Vec<Statement>, CompilerErrorAtLine> {
|
pub fn compile(
|
||||||
let mut compiler = AstCompiler::new(tokens);
|
path: Option<&str>,
|
||||||
|
tokens: Vec<Token>,
|
||||||
|
) -> Result<Vec<Statement>, CompilerErrorAtLine> {
|
||||||
|
let mut compiler = AstCompiler::new(path.unwrap_or(""), tokens);
|
||||||
compiler.compile_tokens()
|
compiler.compile_tokens()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,7 +42,7 @@ struct AstCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AstCompiler {
|
impl AstCompiler {
|
||||||
fn new(tokens: Vec<Token>) -> Self {
|
fn new(_name: &str, tokens: Vec<Token>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
tokens,
|
tokens,
|
||||||
current: 0,
|
current: 0,
|
||||||
|
|
@ -514,7 +518,7 @@ impl AstCompiler {
|
||||||
.vars
|
.vars
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|e| {
|
.filter_map(|e| {
|
||||||
if let Expression::Variable { name, var_type, .. } = e {
|
if let Variable { name, var_type, .. } = e {
|
||||||
Some((name, var_type))
|
Some((name, var_type))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -522,7 +526,7 @@ impl AstCompiler {
|
||||||
})
|
})
|
||||||
.find(|e| e.0 == &token.lexeme)
|
.find(|e| e.0 == &token.lexeme)
|
||||||
.ok_or_else(|| return self.raise(CompilerError::UndeclaredVariable(token.clone())))?;
|
.ok_or_else(|| return self.raise(CompilerError::UndeclaredVariable(token.clone())))?;
|
||||||
Ok(Expression::Variable {
|
Ok(Variable {
|
||||||
name: var_name.to_string(),
|
name: var_name.to_string(),
|
||||||
var_type: var_type.clone(),
|
var_type: var_type.clone(),
|
||||||
line: token.line,
|
line: token.line,
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,11 @@ use crate::vm::{
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub fn compile(
|
pub fn compile(
|
||||||
namespace: Option<&str>,
|
qualified_name: Option<&str>,
|
||||||
ast: &Vec<Statement>,
|
ast: &Vec<Statement>,
|
||||||
registry: &mut HashMap<String, Chunk>,
|
registry: &mut HashMap<String, Chunk>,
|
||||||
) -> Result<(), CompilerErrorAtLine> {
|
) -> Result<(), CompilerErrorAtLine> {
|
||||||
compile_in_namespace(ast, namespace, registry)
|
compile_in_namespace(ast, qualified_name, registry)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn compile_function(
|
pub(crate) fn compile_function(
|
||||||
|
|
@ -24,7 +24,16 @@ pub(crate) fn compile_function(
|
||||||
registry: &mut HashMap<String, Chunk>,
|
registry: &mut HashMap<String, Chunk>,
|
||||||
namespace: &str,
|
namespace: &str,
|
||||||
) -> Result<Chunk, CompilerErrorAtLine> {
|
) -> Result<Chunk, CompilerErrorAtLine> {
|
||||||
let mut compiler = Compiler::new(&function.name.lexeme);
|
let fn_name = &function.name.lexeme;
|
||||||
|
let mut compiler = Compiler::new(fn_name);
|
||||||
|
if is_http_method(fn_name) {
|
||||||
|
compiler.chunk.add_var(&TokenType::StringType, "path");
|
||||||
|
compiler.chunk.add_var(&TokenType::MapType, "query");
|
||||||
|
compiler.chunk.add_var(&TokenType::MapType, "headers");
|
||||||
|
compiler.vars.insert("path".to_string(), 0);
|
||||||
|
compiler.vars.insert("query".to_string(), 1);
|
||||||
|
compiler.vars.insert("headers".to_string(), 2);
|
||||||
|
}
|
||||||
for parm in &function.parameters {
|
for parm in &function.parameters {
|
||||||
let name = parm.name.lexeme.clone();
|
let name = parm.name.lexeme.clone();
|
||||||
let var_index = compiler.chunk.add_var(&parm.var_type, &parm.name.lexeme);
|
let var_index = compiler.chunk.add_var(&parm.var_type, &parm.name.lexeme);
|
||||||
|
|
@ -35,6 +44,10 @@ pub(crate) fn compile_function(
|
||||||
Ok(compiler.compile(&function.body, registry, namespace)?)
|
Ok(compiler.compile(&function.body, registry, namespace)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_http_method(name: &str) -> bool {
|
||||||
|
vec!["get", "post", "put", "delete", "patch"].contains(&name)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn compile_in_namespace(
|
pub(crate) fn compile_in_namespace(
|
||||||
ast: &Vec<Statement>,
|
ast: &Vec<Statement>,
|
||||||
namespace: Option<&str>,
|
namespace: Option<&str>,
|
||||||
|
|
@ -110,7 +123,6 @@ impl Compiler {
|
||||||
}
|
}
|
||||||
Statement::FunctionStmt { function } => {
|
Statement::FunctionStmt { function } => {
|
||||||
let function_name = function.name.lexeme.clone();
|
let function_name = function.name.lexeme.clone();
|
||||||
// self.emit_constant(Value::String(function_name.clone()));
|
|
||||||
let compiled_function = compile_function(function, registry, namespace)?;
|
let compiled_function = compile_function(function, registry, namespace)?;
|
||||||
registry.insert(
|
registry.insert(
|
||||||
format!("{}.{}", self.chunk.name, function_name),
|
format!("{}.{}", self.chunk.name, function_name),
|
||||||
|
|
|
||||||
21
src/lib.rs
21
src/lib.rs
|
|
@ -1,23 +1,23 @@
|
||||||
|
use crate::chunk::Chunk;
|
||||||
|
use crate::errors::Error;
|
||||||
|
use crate::errors::Error::Platform;
|
||||||
use crate::scanner::scan;
|
use crate::scanner::scan;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use crate::vm::interpret;
|
use crate::vm::interpret;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
use crate::chunk::Chunk;
|
|
||||||
use crate::errors::Error;
|
|
||||||
use crate::errors::Error::Platform;
|
|
||||||
|
|
||||||
pub mod ast_compiler;
|
pub mod ast_compiler;
|
||||||
pub mod bytecode_compiler;
|
pub mod bytecode_compiler;
|
||||||
pub mod chunk;
|
pub mod chunk;
|
||||||
mod compiler_tests;
|
mod compiler_tests;
|
||||||
|
pub mod errors;
|
||||||
mod keywords;
|
mod keywords;
|
||||||
pub mod scanner;
|
pub mod scanner;
|
||||||
mod tokens;
|
mod tokens;
|
||||||
mod value;
|
mod value;
|
||||||
pub mod vm;
|
pub mod vm;
|
||||||
pub mod errors;
|
|
||||||
|
|
||||||
pub fn compile_sourcedir(source_dir: &str) -> Result<HashMap<String, Chunk>, Error> {
|
pub fn compile_sourcedir(source_dir: &str) -> Result<HashMap<String, Chunk>, Error> {
|
||||||
let mut registry = HashMap::new();
|
let mut registry = HashMap::new();
|
||||||
|
|
@ -28,12 +28,9 @@ pub fn compile_sourcedir(source_dir:&str)-> Result<HashMap<String,Chunk>, Error>
|
||||||
print!("compiling {:?}: ", path);
|
print!("compiling {:?}: ", path);
|
||||||
let source = fs::read_to_string(path).map_err(map_underlying())?;
|
let source = fs::read_to_string(path).map_err(map_underlying())?;
|
||||||
let tokens = scan(&source)?;
|
let tokens = scan(&source)?;
|
||||||
match ast_compiler::compile(tokens) {
|
match ast_compiler::compile(Some(&path), tokens) {
|
||||||
Ok(statements) => {
|
Ok(statements) => {
|
||||||
let path = path
|
let path = path.strip_prefix("source/").unwrap().replace(".crud", "");
|
||||||
.strip_prefix("source/")
|
|
||||||
.unwrap()
|
|
||||||
.replace(".crud", "");
|
|
||||||
bytecode_compiler::compile(Some(&path), &statements, &mut registry)?;
|
bytecode_compiler::compile(Some(&path), &statements, &mut registry)?;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -51,10 +48,10 @@ pub fn map_underlying() -> fn(std::io::Error) -> Error {
|
||||||
|e| Platform(e.to_string())
|
|e| Platform(e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(src: &str) -> Result<HashMap<String, chunk::Chunk>, Error> {
|
pub fn compile(src: &str) -> Result<HashMap<String, Chunk>, Error> {
|
||||||
let tokens = scan(src)?;
|
let tokens = scan(src)?;
|
||||||
let mut registry = HashMap::new();
|
let mut registry = HashMap::new();
|
||||||
let ast = ast_compiler::compile(tokens)?;
|
let ast = ast_compiler::compile(None, tokens)?;
|
||||||
bytecode_compiler::compile(None, &ast, &mut registry)?;
|
bytecode_compiler::compile(None, &ast, &mut registry)?;
|
||||||
Ok(registry)
|
Ok(registry)
|
||||||
}
|
}
|
||||||
|
|
@ -62,7 +59,7 @@ pub fn compile(src: &str) -> Result<HashMap<String, chunk::Chunk>, Error> {
|
||||||
fn run(src: &str) -> Result<Value, Error> {
|
fn run(src: &str) -> Result<Value, Error> {
|
||||||
let tokens = scan(src)?;
|
let tokens = scan(src)?;
|
||||||
let mut registry = HashMap::new();
|
let mut registry = HashMap::new();
|
||||||
let ast = ast_compiler::compile(tokens)?;
|
let ast = ast_compiler::compile(None, tokens)?;
|
||||||
bytecode_compiler::compile(None, &ast, &mut registry)?;
|
bytecode_compiler::compile(None, &ast, &mut registry)?;
|
||||||
interpret(®istry, "main").map_err(Error::from)
|
interpret(®istry, "main").map_err(Error::from)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
25
src/main.rs
25
src/main.rs
|
|
@ -37,7 +37,7 @@ async fn main() -> Result<(), crudlang::errors::Error> {
|
||||||
axum::serve(listener, app).await.map_err(map_underlying())?;
|
axum::serve(listener, app).await.map_err(map_underlying())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Platform("No source files found".to_string()))
|
Err(Platform("No source files found or compilation error".to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,17 +54,22 @@ async fn handle_any(
|
||||||
let uri = req.uri();
|
let uri = req.uri();
|
||||||
|
|
||||||
// // todo value = Vec<String>
|
// // todo value = Vec<String>
|
||||||
// let query_params: HashMap<String, String> = uri
|
let query_params: HashMap<String, String> = uri
|
||||||
// .query()
|
.query()
|
||||||
// .map(|q| {
|
.map(|q| {
|
||||||
// url::form_urlencoded::parse(q.as_bytes())
|
url::form_urlencoded::parse(q.as_bytes())
|
||||||
// .into_owned()
|
.into_owned()
|
||||||
// .collect()
|
.collect()
|
||||||
// })
|
})
|
||||||
// .unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let component = format!("{}/web.{}", &uri.path()[1..], method);
|
let component = format!("{}/web.{}", &uri.path()[1..], method);
|
||||||
|
|
||||||
|
let mut headers = HashMap::new();
|
||||||
|
for (k,v) in req.headers().iter(){
|
||||||
|
headers.insert(k.to_string(), v.to_str().unwrap().to_string());
|
||||||
|
}
|
||||||
Ok(Json(
|
Ok(Json(
|
||||||
interpret_async(&state.registry, &component, req)
|
interpret_async(&state.registry, &component, &req.uri().to_string(), query_params, headers)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|
|
|
||||||
19
src/vm.rs
19
src/vm.rs
|
|
@ -3,8 +3,8 @@ use crate::errors::RuntimeError::Something;
|
||||||
use crate::errors::{RuntimeError, ValueError};
|
use crate::errors::{RuntimeError, ValueError};
|
||||||
use crate::tokens::TokenType;
|
use crate::tokens::TokenType;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
use axum::http::{Uri};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use axum::extract::Request;
|
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
pub struct Vm<'a> {
|
pub struct Vm<'a> {
|
||||||
|
|
@ -34,7 +34,9 @@ pub fn interpret(registry: &HashMap<String, Chunk>, function: &str) -> Result<Va
|
||||||
pub async fn interpret_async(
|
pub async fn interpret_async(
|
||||||
registry: &HashMap<String, Chunk>,
|
registry: &HashMap<String, Chunk>,
|
||||||
function: &str,
|
function: &str,
|
||||||
_request: Request,
|
uri: &str,
|
||||||
|
query_params: HashMap<String, String>,
|
||||||
|
headers: HashMap<String, String>,
|
||||||
) -> Result<Value, RuntimeError> {
|
) -> Result<Value, RuntimeError> {
|
||||||
//TODO convert request to arguments
|
//TODO convert request to arguments
|
||||||
let chunk = registry.get(function);
|
let chunk = registry.get(function);
|
||||||
|
|
@ -46,12 +48,25 @@ pub async fn interpret_async(
|
||||||
error_occurred: false,
|
error_occurred: false,
|
||||||
registry,
|
registry,
|
||||||
};
|
};
|
||||||
|
vm.local_vars
|
||||||
|
.insert("path".to_string(), Value::String(uri.into()));
|
||||||
|
vm.local_vars
|
||||||
|
.insert("query".to_string(), Value::Map(value_map(query_params)));
|
||||||
|
vm.local_vars
|
||||||
|
.insert("headers".to_string(), Value::Map(value_map(headers)));
|
||||||
vm.run(&chunk)
|
vm.run(&chunk)
|
||||||
} else {
|
} else {
|
||||||
Err(RuntimeError::FunctionNotFound(function.to_string()))
|
Err(RuntimeError::FunctionNotFound(function.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn value_map(strings: HashMap<String, String>) -> HashMap<Value, Value> {
|
||||||
|
strings
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| (Value::String(k.to_string()), Value::String(v.to_string())))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn interpret_function(chunk: &Chunk, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn interpret_function(chunk: &Chunk, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
let mut vm = Vm {
|
let mut vm = Vm {
|
||||||
ip: 0,
|
ip: 0,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue