added main.tp entrypoint

This commit is contained in:
Shautvast 2026-01-13 21:29:45 +01:00
parent 215dc13797
commit 05279201c8
7 changed files with 33 additions and 36 deletions

View file

@ -235,7 +235,3 @@ ISSUES
* improve indenting * improve indenting
WIP guards WIP guards
* | /$uuid -> service.get(uuid)?
| /&first_name -> service.get_by_firstname(first_name)?
| /&last_name -> service.get_by_lastname(last_name)?
| 404

View file

@ -1,18 +1,7 @@
* currently needs postgres on the default port * currently needs postgres on the default port
* user 'postgres' * user 'postgres'
* password 'boompje' * password 'boompje'
* create a table
```
create table customers(
id bigint primary key,
first_name varchar(50),
last_name varchar(50)
)
```
* insert data
```
insert into customers (first_name,last_name) values ('first', 'last')
```
* run ```cargo run -- --source examples/web --watch``` * run ```cargo run -- --source examples/web --watch```
* see ```main.tp``` for the database queries
* and head to http://localhost:3000/api/customer * and head to http://localhost:3000/api/customer
* optionally, adjust the database ddl, update the query in db.tp, and recheck the outpout * optionally, adjust the database ddl, update the query in db.tp, and recheck the outpout

3
examples/web/main.tp Normal file
View file

@ -0,0 +1,3 @@
println("Creating the customers table")
sql("create table if not exists customers(id serial primary key, first_name varchar(50), last_name varchar(50))")
sql("insert into customers (first_name,last_name) values ('first', 'last')")

View file

@ -1,5 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::fs; use std::fs;
use log::info;
use walkdir::WalkDir; use walkdir::WalkDir;
use crate::{symbol_builder, AsmRegistry, TIPI_EXT}; use crate::{symbol_builder, AsmRegistry, TIPI_EXT};
use crate::compiler::assembly_pass::AsmChunk; use crate::compiler::assembly_pass::AsmChunk;
@ -20,7 +21,7 @@ pub fn compile_sourcedir(source_dir: &str) -> Result<HashMap<String, AsmChunk>,
for entry in WalkDir::new(source_dir).into_iter().filter_map(|e| e.ok()) { for entry in WalkDir::new(source_dir).into_iter().filter_map(|e| e.ok()) {
let path = entry.path().to_str().unwrap(); let path = entry.path().to_str().unwrap();
if path.ends_with(TIPI_EXT) { if path.ends_with(TIPI_EXT) {
println!("-- Compiling {} -- ", path); info!("-- 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_pass::scan(&source)?; let tokens = scan_pass::scan(&source)?;
match ast_pass::compile(Some(path), tokens, &mut symbol_table) { match ast_pass::compile(Some(path), tokens, &mut symbol_table) {
@ -64,5 +65,5 @@ pub fn run(src: &str) -> Result<crate::value::Value, TipiLangError> {
let mut asm_registry = HashMap::new(); let mut asm_registry = HashMap::new();
assembly_pass::compile(None, &ast, &symbol_table, &mut asm_registry)?; assembly_pass::compile(None, &ast, &symbol_table, &mut asm_registry)?;
let registry = arc_swap::ArcSwap::from(std::sync::Arc::new(asm_registry)); let registry = arc_swap::ArcSwap::from(std::sync::Arc::new(asm_registry));
crate::vm::interpret(registry.load(), "main").map_err(TipiLangError::from) crate::vm::run(registry.load(), "main").map_err(TipiLangError::from)
} }

View file

@ -17,12 +17,13 @@ pub fn start_watch_daemon(source: &str, registry: Arc<ArcSwap<HashMap<String, As
let s = source.to_string(); let s = source.to_string();
let (tx, rx) = channel(); let (tx, rx) = channel();
thread::spawn(move || { thread::spawn(move || {
println!("-- File watch started --"); info!("-- File watch started --");
let path = Path::new(&source); let path = Path::new(&source);
if !path.exists() { if !path.exists() {
panic!("source directory {} does not exist", &source); panic!("source directory {} does not exist", &source);
} }
let mut watcher = notify::recommended_watcher(tx).expect("Failed to create watcher"); let mut watcher = notify::recommended_watcher(tx)
.expect("Failed to create watcher");
watcher watcher
.watch(path, RecursiveMode::Recursive) .watch(path, RecursiveMode::Recursive)
.expect("Failed to watch"); .expect("Failed to watch");

View file

@ -5,17 +5,17 @@ use axum::routing::any;
use axum::{Json, Router}; use axum::{Json, Router};
use bb8_postgres::PostgresConnectionManager; use bb8_postgres::PostgresConnectionManager;
use clap::Parser; use clap::Parser;
use log::info; use log::{error, info};
use std::collections::HashMap; use std::collections::HashMap;
use std::fs; use std::fs;
use std::sync::{Arc, LazyLock, OnceLock}; use std::sync::{Arc, LazyLock, OnceLock};
use tipi_lang::compiler::assembly_pass::AsmChunk; use tipi_lang::compiler::assembly_pass::AsmChunk;
use tipi_lang::compiler::{compile_sourcedir, map_underlying, run}; use tipi_lang::compiler::{compile_sourcedir, map_underlying, run};
use tipi_lang::errors::TipiLangError; use tipi_lang::errors::TipiLangError;
use tipi_lang::vm::interpret_async;
use tokio_postgres::NoTls;
use tipi_lang::DB_POOL;
use tipi_lang::value::Value; use tipi_lang::value::Value;
use tipi_lang::vm::run_async;
use tipi_lang::{DB_POOL, vm};
use tokio_postgres::NoTls;
/// A simple CLI tool to greet users /// A simple CLI tool to greet users
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -36,9 +36,11 @@ struct Args {
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), TipiLangError> { async fn main() -> Result<(), TipiLangError> {
//TODO make configurable //TODO make configurable
let manager = let manager = PostgresConnectionManager::new_from_stringlike(
PostgresConnectionManager::new_from_stringlike("host=localhost user=postgres password=boompje", NoTls) "host=localhost user=postgres password=boompje",
.unwrap(); NoTls,
)
.unwrap();
let pool = bb8::Pool::builder() let pool = bb8::Pool::builder()
.build(manager) .build(manager)
.await .await
@ -51,17 +53,22 @@ async fn main() -> Result<(), TipiLangError> {
let source = fs::read_to_string(file).expect("Unable to read file"); let source = fs::read_to_string(file).expect("Unable to read file");
run(&source)?; run(&source)?;
} else { } else {
println!("-- Tipilang --"); info!("-- Tipilang --");
let source = args.source.unwrap_or("./source".to_string()); let source = args.source.unwrap_or("./source".to_string());
let registry = compile_sourcedir(&source)?; let registry = compile_sourcedir(&source)?;
let empty = registry.is_empty(); let empty = registry.is_empty();
let swap = Arc::new(ArcSwap::from(Arc::new(registry))); let swap = Arc::new(ArcSwap::from(Arc::new(registry)));
if !empty { if !empty {
let registry = swap.clone().load();
if let Some(main) = registry.get("/main") {
vm::run(registry, "/main")?;
}
if args.watch { if args.watch {
tipi_lang::file_watch::start_watch_daemon(&source, swap.clone()); tipi_lang::file_watch::start_watch_daemon(&source, swap.clone());
} }
println!("-- Compilation successful --"); info!("-- Compilation successful --");
let state = AppState { let state = AppState {
registry: swap.clone(), registry: swap.clone(),
}; };
@ -73,7 +80,7 @@ async fn main() -> Result<(), TipiLangError> {
.await .await
.map_err(map_underlying())?; .map_err(map_underlying())?;
println!( info!(
"-- Listening on {} --\n", "-- Listening on {} --\n",
listener.local_addr().map_err(map_underlying())? listener.local_addr().map_err(map_underlying())?
); );
@ -84,7 +91,7 @@ async fn main() -> Result<(), TipiLangError> {
axum::serve(listener, app).await.map_err(map_underlying())?; axum::serve(listener, app).await.map_err(map_underlying())?;
} else { } else {
println!("No source files found or compilation error"); error!("No source files found or compilation error");
if args.repl { if args.repl {
tipi_lang::repl::start(swap.clone())?; tipi_lang::repl::start(swap.clone())?;
} }
@ -123,7 +130,7 @@ async fn handle_any(
} }
let path = &req.uri().to_string(); let path = &req.uri().to_string();
info!("invoked {:?} => {}", req, function_qname); info!("invoked {:?} => {}", req, function_qname);
match interpret_async( match run_async(
state.registry.load(), state.registry.load(),
&function_qname, &function_qname,
path, path,

View file

@ -10,7 +10,7 @@ use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
pub async fn interpret_async( pub async fn run_async(
registry: Guard<Arc<HashMap<String, AsmChunk>>>, registry: Guard<Arc<HashMap<String, AsmChunk>>>,
function: &str, function: &str,
uri: &str, uri: &str,
@ -38,13 +38,13 @@ pub async fn interpret_async(
} }
} }
pub fn interpret(registry: Guard<Arc<AsmRegistry>>, function: &str) -> Result<Value, RuntimeError> { pub fn run(registry: Guard<Arc<AsmRegistry>>, function: &str) -> Result<Value, RuntimeError> {
let chunk = registry.get(function).unwrap().clone(); let chunk = registry.get(function).unwrap().clone();
let mut vm = Vm::new(&registry); let mut vm = Vm::new(&registry);
vm.run(&get_context(function), &chunk) vm.run(&get_context(function), &chunk)
} }
pub fn interpret_function(chunk: &AsmChunk, args: Vec<Value>, registry: Arc<AsmRegistry>) -> Result<Value, RuntimeError> { pub fn run_function(chunk: &AsmChunk, args: Vec<Value>, registry: Arc<AsmRegistry>) -> Result<Value, RuntimeError> {
let mut vm = Vm::new(&registry); let mut vm = Vm::new(&registry);
vm.run_function(chunk, args) vm.run_function(chunk, args)
} }
@ -241,7 +241,7 @@ impl Vm {
return Err(RuntimeError::FunctionNotFound(function_name)); return Err(RuntimeError::FunctionNotFound(function_name));
} }
} else { } else {
let result = interpret_function(function_chunk.unwrap(), args, self.registry.clone())?; let result = run_function(function_chunk.unwrap(), args, self.registry.clone())?;
self.push(Rc::new(RefCell::new(result))); self.push(Rc::new(RefCell::new(result)));
} }
} }