parent
14fe23f780
commit
7706b95125
@ -0,0 +1,173 @@
|
|||||||
|
REM This is an example of a more complex program,
|
||||||
|
REM which spawns procedural waves
|
||||||
|
|
||||||
|
LET wave = 0
|
||||||
|
LET timeout = @time + 120000
|
||||||
|
|
||||||
|
initial_wait:
|
||||||
|
LET remaining = timeout - @time
|
||||||
|
IF remaining <= 0 THEN
|
||||||
|
GOTO main
|
||||||
|
END IF
|
||||||
|
|
||||||
|
PRINT "[red]Enemies[white] approaching: "
|
||||||
|
PRINT ceil(remaining / 1000), " s"
|
||||||
|
PRINT_MESSAGE_MISSION()
|
||||||
|
|
||||||
|
wait(0.5)
|
||||||
|
|
||||||
|
GOTO initial_wait
|
||||||
|
main:
|
||||||
|
wave = wave + 1
|
||||||
|
REM TODO: difficult control wave multiplier
|
||||||
|
LET progression = POW(wave / 4, 0.75)
|
||||||
|
REM TODO: optimize duplicate operations
|
||||||
|
progression = MIN(progression / 2 + rand(progression / 2), 10)
|
||||||
|
|
||||||
|
LET units = 2 + SQRT(progression) * 4 + RAND(progression * 2)
|
||||||
|
REM TODO: difficulty control unit amount
|
||||||
|
units = CEIL(units * 1)
|
||||||
|
LET tank_units = FLOOR(RAND(units))
|
||||||
|
LET mech_units = FLOOR(RAND(units - tank_units))
|
||||||
|
LET air_units = units - tank_units - mech_units
|
||||||
|
|
||||||
|
LET spawnx = 30
|
||||||
|
LET spawny = 50
|
||||||
|
|
||||||
|
GOTO spawn_tank
|
||||||
|
spawn_tank_end:
|
||||||
|
GOTO spawn_mech
|
||||||
|
spawn_mech_end:
|
||||||
|
LET spawnx = 20
|
||||||
|
GOTO spawn_air
|
||||||
|
spawn_air_end:
|
||||||
|
|
||||||
|
WRITE(wave, cell1, 1)
|
||||||
|
READ(timeout, cell1, 0)
|
||||||
|
timeout = @time + timeout * 1000
|
||||||
|
|
||||||
|
main_wait:
|
||||||
|
LET remaining = timeout - @time
|
||||||
|
IF remaining <= 0 THEN
|
||||||
|
GOTO main
|
||||||
|
END IF
|
||||||
|
|
||||||
|
PRINT "[yellow]Wave ", wave, "[white] - "
|
||||||
|
PRINT "Next wave: ", ceil(remaining / 1000), " s"
|
||||||
|
PRINT_MESSAGE_MISSION()
|
||||||
|
|
||||||
|
wait(0.5)
|
||||||
|
|
||||||
|
GOTO main_wait
|
||||||
|
|
||||||
|
spawn_tank:
|
||||||
|
LET spawned = 0
|
||||||
|
spawn_tank_loop:
|
||||||
|
LET roll = rand(progression)
|
||||||
|
IF roll >= 3 THEN
|
||||||
|
IF roll >= 4 THEN
|
||||||
|
SPAWN(@conquer, spawnx, spawny, 0, @crux, _)
|
||||||
|
spawnx = spawnx - 5.75
|
||||||
|
ELSE
|
||||||
|
SPAWN(@vanquish, spawnx, spawny, 0, @crux, _)
|
||||||
|
spawnx = spawnx - 3.5
|
||||||
|
END IF
|
||||||
|
ELSE
|
||||||
|
IF roll >= 2 THEN
|
||||||
|
SPAWN(@precept, spawnx, spawny, 0, @crux, _)
|
||||||
|
spawnx = spawnx - 3.25
|
||||||
|
ELSE
|
||||||
|
REM Small units can unclump easily
|
||||||
|
IF roll >= 1 THEN
|
||||||
|
SPAWN(@locus, spawnx, spawny, 0, @crux, _)
|
||||||
|
spawnx = spawnx - 1.0
|
||||||
|
ELSE
|
||||||
|
SPAWN(@stell, spawnx, spawny, 0, @crux, _)
|
||||||
|
spawnx = spawnx - 1.0
|
||||||
|
END IF
|
||||||
|
END IF
|
||||||
|
END IF
|
||||||
|
|
||||||
|
IF spawnx < 10 THEN
|
||||||
|
spawnx = 10
|
||||||
|
END IF
|
||||||
|
|
||||||
|
spawned = spawned + 1
|
||||||
|
IF spawned < tank_units THEN
|
||||||
|
GOTO spawn_tank_loop
|
||||||
|
END IF
|
||||||
|
GOTO spawn_tank_end
|
||||||
|
|
||||||
|
spawn_mech:
|
||||||
|
LET spawned = 0
|
||||||
|
spawn_mech_loop:
|
||||||
|
LET roll = rand(progression)
|
||||||
|
IF roll >= 3 THEN
|
||||||
|
IF roll >= 4 THEN
|
||||||
|
SPAWN(@collaris, spawnx, spawny, 0, @crux, _)
|
||||||
|
spawnx = spawnx - 5.5
|
||||||
|
ELSE
|
||||||
|
SPAWN(@tecta, spawnx, spawny, 0, @crux, _)
|
||||||
|
spawnx = spawnx - 2.87
|
||||||
|
END IF
|
||||||
|
ELSE
|
||||||
|
IF roll >= 2 THEN
|
||||||
|
SPAWN(@anthicus, spawnx, spawny, 0, @crux, _)
|
||||||
|
spawnx = spawnx - 2.62
|
||||||
|
ELSE
|
||||||
|
IF roll >= 1 THEN
|
||||||
|
SPAWN(@cleroi, spawnx, spawny, 0, @crux, _)
|
||||||
|
spawnx = spawnx - 1.0
|
||||||
|
ELSE
|
||||||
|
SPAWN(@merui, spawnx, spawny, 0, @crux, _)
|
||||||
|
spawnx = spawnx - 1.0
|
||||||
|
END IF
|
||||||
|
END IF
|
||||||
|
END IF
|
||||||
|
|
||||||
|
IF spawnx < 10 THEN
|
||||||
|
spawnx = 10
|
||||||
|
END IF
|
||||||
|
|
||||||
|
spawned = spawned + 1
|
||||||
|
IF spawned < mech_units THEN
|
||||||
|
GOTO spawn_mech_loop
|
||||||
|
END IF
|
||||||
|
GOTO spawn_mech_end
|
||||||
|
|
||||||
|
spawn_air:
|
||||||
|
LET spawned = 0
|
||||||
|
spawn_air_loop:
|
||||||
|
LET roll = rand(progression)
|
||||||
|
IF roll >= 3 THEN
|
||||||
|
IF roll >= 4 THEN
|
||||||
|
SPAWN(@disrupt, spawnx, spawny, 0, @crux, _)
|
||||||
|
spawnx = spawnx - 5.75
|
||||||
|
ELSE
|
||||||
|
SPAWN(@quell, spawnx, spawny, 0, @crux, _)
|
||||||
|
spawnx = spawnx - 4.5
|
||||||
|
END IF
|
||||||
|
ELSE
|
||||||
|
IF roll >= 2 THEN
|
||||||
|
SPAWN(@obviate, spawnx, spawny, 0, @crux, _)
|
||||||
|
spawnx = spawnx - 3.12
|
||||||
|
ELSE
|
||||||
|
IF roll >= 1 THEN
|
||||||
|
SPAWN(@avert, spawnx, spawny, 0, @crux, _)
|
||||||
|
spawnx = spawnx - 1
|
||||||
|
ELSE
|
||||||
|
SPAWN(@elude, spawnx, spawny, 0, @crux, _)
|
||||||
|
spawnx = spawnx - 1
|
||||||
|
END IF
|
||||||
|
END IF
|
||||||
|
END IF
|
||||||
|
|
||||||
|
IF spawnx < 10 THEN
|
||||||
|
spawnx = 10
|
||||||
|
END IF
|
||||||
|
|
||||||
|
spawned = spawned + 1
|
||||||
|
IF spawned < air_units THEN
|
||||||
|
GOTO spawn_air_loop
|
||||||
|
END IF
|
||||||
|
GOTO spawn_air_end
|
@ -0,0 +1,127 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||||
|
pub enum Operator {
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
Mod,
|
||||||
|
RShift,
|
||||||
|
LShift,
|
||||||
|
Gt,
|
||||||
|
Lt,
|
||||||
|
Gte,
|
||||||
|
Lte,
|
||||||
|
Eq,
|
||||||
|
Neq,
|
||||||
|
Max,
|
||||||
|
Min,
|
||||||
|
Pow,
|
||||||
|
// etc.
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operator {
|
||||||
|
pub(crate) fn precedence(self) -> u8 {
|
||||||
|
use Operator as O;
|
||||||
|
match self {
|
||||||
|
O::Add | O::Sub => 3,
|
||||||
|
O::RShift | O::LShift => 4,
|
||||||
|
O::Mod => 5,
|
||||||
|
O::Mul | O::Div => 10,
|
||||||
|
O::Eq | O::Neq | O::Gt | O::Lt | O::Gte | O::Lte => 0,
|
||||||
|
_ => 128,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_fn_name(raw: &str) -> Option<Self> {
|
||||||
|
match raw {
|
||||||
|
"max" => Some(Self::Max),
|
||||||
|
"min" => Some(Self::Min),
|
||||||
|
"pow" => Some(Self::Pow),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn format_operator(operator: Operator) -> &'static str {
|
||||||
|
match operator {
|
||||||
|
Operator::Eq => "equal",
|
||||||
|
Operator::Neq => "notEqual",
|
||||||
|
Operator::Lt => "lessThan",
|
||||||
|
Operator::Lte => "lessThanEq",
|
||||||
|
Operator::Gt => "greaterThan",
|
||||||
|
Operator::Gte => "greaterThanEq",
|
||||||
|
Operator::Add => "add",
|
||||||
|
Operator::Sub => "sub",
|
||||||
|
Operator::Mul => "mul",
|
||||||
|
Operator::Div => "div",
|
||||||
|
Operator::Mod => "mod",
|
||||||
|
Operator::RShift => "shr",
|
||||||
|
Operator::LShift => "shl",
|
||||||
|
Operator::Max => "max",
|
||||||
|
Operator::Min => "min",
|
||||||
|
Operator::Pow => "pow",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||||
|
pub enum UnaryOperator {
|
||||||
|
Floor,
|
||||||
|
Round,
|
||||||
|
Ceil,
|
||||||
|
Rand,
|
||||||
|
Sqrt,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for UnaryOperator {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
"floor" => Ok(Self::Floor),
|
||||||
|
"round" => Ok(Self::Round),
|
||||||
|
"ceil" => Ok(Self::Ceil),
|
||||||
|
"rand" => Ok(Self::Rand),
|
||||||
|
"sqrt" => Ok(Self::Sqrt),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn format_unary_operator(operator: UnaryOperator) -> &'static str {
|
||||||
|
match operator {
|
||||||
|
UnaryOperator::Floor => "floor",
|
||||||
|
UnaryOperator::Round => "round",
|
||||||
|
UnaryOperator::Ceil => "ceil",
|
||||||
|
UnaryOperator::Rand => "rand",
|
||||||
|
UnaryOperator::Sqrt => "sqrt",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Config {
|
||||||
|
pub builtin_functions: HashMap<String, (String, usize)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Config {
|
||||||
|
fn default() -> Self {
|
||||||
|
macro_rules! builtin_function {
|
||||||
|
( $name:expr, $target_name:expr, $n_args:expr ) => {
|
||||||
|
(String::from($name), (String::from($target_name), $n_args))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
builtin_functions: HashMap::from([
|
||||||
|
builtin_function!("print_flush", "printflush", 1),
|
||||||
|
builtin_function!("print_message_mission", "message mission", 0),
|
||||||
|
builtin_function!("read", "read", 3),
|
||||||
|
builtin_function!("write", "write", 3),
|
||||||
|
builtin_function!("wait", "wait", 1),
|
||||||
|
builtin_function!("set_flag", "setflag", 2),
|
||||||
|
builtin_function!("get_flag", "getflag", 2),
|
||||||
|
builtin_function!("spawn", "spawn", 6),
|
||||||
|
]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
pub mod common;
|
||||||
pub mod compile;
|
pub mod compile;
|
||||||
pub mod cursor;
|
pub mod cursor;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use basic_to_mindustry::common::Config;
|
||||||
|
use basic_to_mindustry::compile::{optimize_set_use, translate_ast};
|
||||||
|
use basic_to_mindustry::parse::{build_ast, tokenize};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
let config = Config::default();
|
||||||
|
for entry in Path::new("./examples/").read_dir().unwrap() {
|
||||||
|
let Ok(entry) = entry else { continue };
|
||||||
|
if entry
|
||||||
|
.file_name()
|
||||||
|
.into_string()
|
||||||
|
.map(|name| name.ends_with(".basic"))
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
let file_name = entry.file_name().into_string().unwrap();
|
||||||
|
let file = std::fs::read_to_string(entry.path()).unwrap_or_else(|e| {
|
||||||
|
panic!("Error opening {:?}: {:?}", file_name, e);
|
||||||
|
});
|
||||||
|
|
||||||
|
let tokenized = tokenize(&file).unwrap_or_else(|e| {
|
||||||
|
panic!("Error tokenizing {:?}: {:?}", file_name, e);
|
||||||
|
});
|
||||||
|
let parsed = build_ast(&tokenized, &config).unwrap_or_else(|e| {
|
||||||
|
panic!("Error parsing {:?}: {:?}", file_name, e);
|
||||||
|
});
|
||||||
|
let translated = translate_ast(&parsed, &mut Default::default(), &config);
|
||||||
|
let optimized = optimize_set_use(translated);
|
||||||
|
|
||||||
|
let _ = optimized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue