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():
|
||||
#path(/) -> list:
|
||||
| path == "/" -> list:
|
||||
service.get_all()
|
||||
|
||||
#path(/id/{uuid}) -> Customer?:
|
||||
| path == "/{uuid}" -> Customer?:
|
||||
service.get(uuid)?
|
||||
|
||||
#path(?firstname={fname} | lastname={lname}) -> Customer?:
|
||||
if name:
|
||||
service.get_by_firstname(fname)?
|
||||
else if lastname:
|
||||
service.get_by_lastname(lname)?
|
||||
else:
|
||||
404
|
||||
| path == "/" && query.firstname -> Customer?:
|
||||
service.get_by_firstname(fname)?
|
||||
| path == "/" && query.last_name -> Customer?
|
||||
service.get_by_lastname(lname)?
|
||||
| 404
|
||||
|
||||
fn post(customer: Customer):
|
||||
service.add(customer)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
fn get() -> string:
|
||||
add("hello", "world")
|
||||
fn get(path: string) -> string:
|
||||
add("hello", path)
|
||||
|
||||
fn add(a: string, b: string) -> string:
|
||||
a + " " + b
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use crate::ast_compiler::Expression::Variable;
|
||||
use crate::errors::CompilerError::{
|
||||
self, Expected, IncompatibleTypes, ParseError, TooManyParameters, TypeError, UnexpectedIndent,
|
||||
UninitializedVariable,
|
||||
|
|
@ -15,8 +16,11 @@ use crate::value::Value;
|
|||
use log::debug;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn compile(tokens: Vec<Token>) -> Result<Vec<Statement>, CompilerErrorAtLine> {
|
||||
let mut compiler = AstCompiler::new(tokens);
|
||||
pub fn compile(
|
||||
path: Option<&str>,
|
||||
tokens: Vec<Token>,
|
||||
) -> Result<Vec<Statement>, CompilerErrorAtLine> {
|
||||
let mut compiler = AstCompiler::new(path.unwrap_or(""), tokens);
|
||||
compiler.compile_tokens()
|
||||
}
|
||||
|
||||
|
|
@ -38,7 +42,7 @@ struct AstCompiler {
|
|||
}
|
||||
|
||||
impl AstCompiler {
|
||||
fn new(tokens: Vec<Token>) -> Self {
|
||||
fn new(_name: &str, tokens: Vec<Token>) -> Self {
|
||||
Self {
|
||||
tokens,
|
||||
current: 0,
|
||||
|
|
@ -514,7 +518,7 @@ impl AstCompiler {
|
|||
.vars
|
||||
.iter()
|
||||
.filter_map(|e| {
|
||||
if let Expression::Variable { name, var_type, .. } = e {
|
||||
if let Variable { name, var_type, .. } = e {
|
||||
Some((name, var_type))
|
||||
} else {
|
||||
None
|
||||
|
|
@ -522,7 +526,7 @@ impl AstCompiler {
|
|||
})
|
||||
.find(|e| e.0 == &token.lexeme)
|
||||
.ok_or_else(|| return self.raise(CompilerError::UndeclaredVariable(token.clone())))?;
|
||||
Ok(Expression::Variable {
|
||||
Ok(Variable {
|
||||
name: var_name.to_string(),
|
||||
var_type: var_type.clone(),
|
||||
line: token.line,
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@ use crate::vm::{
|
|||
use std::collections::HashMap;
|
||||
|
||||
pub fn compile(
|
||||
namespace: Option<&str>,
|
||||
qualified_name: Option<&str>,
|
||||
ast: &Vec<Statement>,
|
||||
registry: &mut HashMap<String, Chunk>,
|
||||
) -> Result<(), CompilerErrorAtLine> {
|
||||
compile_in_namespace(ast, namespace, registry)
|
||||
compile_in_namespace(ast, qualified_name, registry)
|
||||
}
|
||||
|
||||
pub(crate) fn compile_function(
|
||||
|
|
@ -24,7 +24,16 @@ pub(crate) fn compile_function(
|
|||
registry: &mut HashMap<String, Chunk>,
|
||||
namespace: &str,
|
||||
) -> 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 {
|
||||
let name = parm.name.lexeme.clone();
|
||||
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)?)
|
||||
}
|
||||
|
||||
fn is_http_method(name: &str) -> bool {
|
||||
vec!["get", "post", "put", "delete", "patch"].contains(&name)
|
||||
}
|
||||
|
||||
pub(crate) fn compile_in_namespace(
|
||||
ast: &Vec<Statement>,
|
||||
namespace: Option<&str>,
|
||||
|
|
@ -110,7 +123,6 @@ impl Compiler {
|
|||
}
|
||||
Statement::FunctionStmt { function } => {
|
||||
let function_name = function.name.lexeme.clone();
|
||||
// self.emit_constant(Value::String(function_name.clone()));
|
||||
let compiled_function = compile_function(function, registry, namespace)?;
|
||||
registry.insert(
|
||||
format!("{}.{}", self.chunk.name, function_name),
|
||||
|
|
|
|||
23
src/lib.rs
23
src/lib.rs
|
|
@ -1,25 +1,25 @@
|
|||
use crate::chunk::Chunk;
|
||||
use crate::errors::Error;
|
||||
use crate::errors::Error::Platform;
|
||||
use crate::scanner::scan;
|
||||
use crate::value::Value;
|
||||
use crate::vm::interpret;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use walkdir::WalkDir;
|
||||
use crate::chunk::Chunk;
|
||||
use crate::errors::Error;
|
||||
use crate::errors::Error::Platform;
|
||||
|
||||
pub mod ast_compiler;
|
||||
pub mod bytecode_compiler;
|
||||
pub mod chunk;
|
||||
mod compiler_tests;
|
||||
pub mod errors;
|
||||
mod keywords;
|
||||
pub mod scanner;
|
||||
mod tokens;
|
||||
mod value;
|
||||
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();
|
||||
|
||||
for entry in WalkDir::new(source_dir).into_iter().filter_map(|e| e.ok()) {
|
||||
|
|
@ -28,12 +28,9 @@ pub fn compile_sourcedir(source_dir:&str)-> Result<HashMap<String,Chunk>, Error>
|
|||
print!("compiling {:?}: ", path);
|
||||
let source = fs::read_to_string(path).map_err(map_underlying())?;
|
||||
let tokens = scan(&source)?;
|
||||
match ast_compiler::compile(tokens) {
|
||||
match ast_compiler::compile(Some(&path), tokens) {
|
||||
Ok(statements) => {
|
||||
let path = path
|
||||
.strip_prefix("source/")
|
||||
.unwrap()
|
||||
.replace(".crud", "");
|
||||
let path = path.strip_prefix("source/").unwrap().replace(".crud", "");
|
||||
bytecode_compiler::compile(Some(&path), &statements, &mut registry)?;
|
||||
}
|
||||
Err(e) => {
|
||||
|
|
@ -51,10 +48,10 @@ pub fn map_underlying() -> fn(std::io::Error) -> Error {
|
|||
|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 mut registry = HashMap::new();
|
||||
let ast = ast_compiler::compile(tokens)?;
|
||||
let ast = ast_compiler::compile(None, tokens)?;
|
||||
bytecode_compiler::compile(None, &ast, &mut 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> {
|
||||
let tokens = scan(src)?;
|
||||
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)?;
|
||||
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())?;
|
||||
Ok(())
|
||||
} 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();
|
||||
|
||||
// // todo value = Vec<String>
|
||||
// let query_params: HashMap<String, String> = uri
|
||||
// .query()
|
||||
// .map(|q| {
|
||||
// url::form_urlencoded::parse(q.as_bytes())
|
||||
// .into_owned()
|
||||
// .collect()
|
||||
// })
|
||||
// .unwrap_or_default();
|
||||
let query_params: HashMap<String, String> = uri
|
||||
.query()
|
||||
.map(|q| {
|
||||
url::form_urlencoded::parse(q.as_bytes())
|
||||
.into_owned()
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
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(
|
||||
interpret_async(&state.registry, &component, req)
|
||||
interpret_async(&state.registry, &component, &req.uri().to_string(), query_params, headers)
|
||||
.await
|
||||
.unwrap()
|
||||
.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::tokens::TokenType;
|
||||
use crate::value::Value;
|
||||
use axum::http::{Uri};
|
||||
use std::collections::HashMap;
|
||||
use axum::extract::Request;
|
||||
use tracing::debug;
|
||||
|
||||
pub struct Vm<'a> {
|
||||
|
|
@ -34,7 +34,9 @@ pub fn interpret(registry: &HashMap<String, Chunk>, function: &str) -> Result<Va
|
|||
pub async fn interpret_async(
|
||||
registry: &HashMap<String, Chunk>,
|
||||
function: &str,
|
||||
_request: Request,
|
||||
uri: &str,
|
||||
query_params: HashMap<String, String>,
|
||||
headers: HashMap<String, String>,
|
||||
) -> Result<Value, RuntimeError> {
|
||||
//TODO convert request to arguments
|
||||
let chunk = registry.get(function);
|
||||
|
|
@ -46,12 +48,25 @@ pub async fn interpret_async(
|
|||
error_occurred: false,
|
||||
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)
|
||||
} else {
|
||||
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> {
|
||||
let mut vm = Vm {
|
||||
ip: 0,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue