Skip to content

Commit

Permalink
bruh
Browse files Browse the repository at this point in the history
  • Loading branch information
JonathanWoollett-Light committed Jun 14, 2024
1 parent 1457a8f commit 8ed22c2
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 201 deletions.
2 changes: 0 additions & 2 deletions core.abc
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ macro type_integer_i64 7

macro value_literal 0
macro value_variable 1
macro value_type 2
macro value_register 3

# making `if` and `loop` functions requires adding the ability for functions to
# manipualte the AST under them, so for now they are intrinsics until this
Expand Down
36 changes: 18 additions & 18 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@
</nav>
<h4>🚧Given the early state of development anything and everything might not work🚧</h4>
<ul>
<li><b>Less keywords than C.</b></li>
<li><b>No stack overflow.</b></li>
<li><b>No generics/templates.</b></li>
<li><b>No macros.</b></li>
<li><b>No hidden memory allocations.</b></li>
<li><b>Full type inference with formal verification.</b></li>
<li><b>Fewer keywords than C.</b> <i>"An idiot admires complexity, a genius admires simplicity"</i> - Terry A Davis</li>
<li><b>Infallible type inference</b> unlike Rust which constantly fails to infer type infomation.</li>
<li><b>No stack overflow</b> becuase there is no recursion. There is always a better iterative solution.</li>
<li><b>No hidden memory allocations</b> unlike Zig which still does fallible stack allocation.</li>
<li><b>Formal verification</b> like <a href="https://ada-lang.io/">Ada</a> but simpler.</li>
<li><b>No generics or templates</b> becuase it doesn't need hints to figure out the types that work.</li>
</ul>
<p>Supports aarch64.<br>Doesn't support RISC-V.<br>Won't support x86-64.</p>
<h3>Hello, World!</h3>
Expand All @@ -59,27 +59,27 @@ <h5>Rust</h5>
</div>
<h3>Keywords</h3>
<ol>
<li><span class="code">if</span>: If <span class="code">x0</span> contains <span class="code">1</span> runs the indented code.</li>
<li><span class="code">loop</span>: <a href="https://doc.rust-lang.org/rust-by-example/flow_control/loop.html">Rust's <span class="code">loop</span></a> without the brackets.</li>
<li><span class="code">break</span>: Jumps out of the current <span class="code">loop</span>.</li>
<li><span class="code">if</span>: <a href="https://doc.rust-lang.org/rust-by-example/flow_control/if_else.html">Rust's <span class="code">if</span></a> without the brackets*.</li>
<li><span class="code">loop</span>: <a href="https://doc.rust-lang.org/rust-by-example/flow_control/loop.html">Rust's <span class="code">loop</span></a> without the brackets*.</li>
<li><span class="code">break</span>: Jumps out of the current <span class="code">loop</span>*.</li>
<li><span class="code">def</span>: <a href="https://www.w3schools.com/python/python_functions.asp">Python's <span class="code">def</span></a> without the <span class="code">:</span>.</li>
<li><span class="code">in</span>: The arguments given to a function.</li>
<li><span class="code">in</span>: The arguments given to a function**.</li>
<li><span class="code">out</span>: The output given to a function. <span class="code">a := b - c + d</span> after unrolling and type inference is equivalent to <p class="code">c + d @ x<br>b - x @ y<br>a := y @ null</p><span class="code">@</span> can only be defined on the outermost expression in a line, the outputs of nested expression are used to chain the expressions together.</li>
<li><span class="code">fail</span>: If reachable triggers a failure in formal verification.</li>
<li><span class="code">assume</span>: Mark code which will be passed to formal verification but excluded at run-time e.g. <span class="code">x %= 4</span> tells the verifier <span class="code">{ 0 ≤ x &lt 4 }</span>.</li>
<li><span class="code">typeof</span>: Get the type of a value.</li>
<li><span class="code">valueof</span>: Get the value of a value.</li>
<li><span class="code">assume</span>: Mark code which will be passed to formal verification but excluded at run-time. <span class="code">assume x %= 4</span> tells the verifier <span class="code">{ 0 ≤ x &lt 4 }</span>.</li>
<li><span class="code">valueof</span>: Gets the value of a value.<p class="code">a := valueof 1 // a = value_literal = 0<br>b := valueof c // b = value_variable (1)</p></li>
<li><span class="code">unreachable</span>: Marks the end of execution, all following statements are unreachable.</li>
<li><span class="code">macro</span>: Similar to <a href="https://gcc.gnu.org/onlinedocs/cpp/Macros.html">macros in C</a>. Macro evaluation happens before the AST is parsed and simply performs a find and replace on the text contents of source files. Since <span class="code">:=</span> is a function, <span class="code">macro</span> is how constants used in the definition of <span class="code">:=</span> are defined. Unless writing your own core, you should never need to use this.</li>
<li><span class="code">asm</span>: The prefix for a line with in-line assembly e.g. <span class="code">asm mov x0, 1</span>.</li>
</ol>
<p>* <span class="code">if</span>, <span class="code">loop</span> and <span class="code">break</span> will be removed as intrinsics and added to the core library as functions when the compiler is re-written in the language. At this point functions will be able to mutate their child AST. This will enable equivalent support to <a href="https://doc.rust-lang.org/reference/procedural-macros.html">procedural macros found in other languages</a> but better.</p>
<p>** I'm thinking about splitting <span class="code">in</span> into <span class="code">lhs</span> and <span class="code">rhs</span> as this will make all input patterns differentiable to a function. Currently with <span class="code">in</span> when you have a function <span class="code">my_function</span> calling it with <span class="code">a my_function b</span> or <span class="code">my_function a b</span> appears identical to the function.</p>
<h3>Tentative keywords</h3>
<ol>
<li><span class="code">comptime</span>: Forces evaluation at compile-time.</li>
<li><span class="code">assert</span>: A condition that calls <span class="code">exit</span> if false at run-time.</li>
<li><span class="code">assert</span>: A condition that calls <span class="code">exit</span> if false at run-time. This will tie into some mechanism to auto-generate unique error codes.</li>
<li><span class="code">verify</span>: Like <span class="code">require</span> but does not exhaustively check the condition. <span class="code">verify x < 2</span> will apply a number of steps of gradient descent to search for the minium of <span class="code">x</span> to verify the condition. While this is not formal verification it provides an effective and almost always correct mechanism to test conditions at compile time that would be too computationally expensive to exhaustively prove.</li>
<li><span class="code">abstain</span>: Resets the understood domain of a variable at compile to any value.</li>
<li><span class="code">clone</span>: Marks the split of execution into multiple threads.</li>
<li><span class="code">ast</span>: Gets the AST of code indented under a function call.</li>
<li><span class="code">inline</span>: Inline an AST as if it where source code at this location.</li>
<li><span class="code">ast</span>: Gets the AST of code indented under a function call. This can then be edited so a function may perform the role of a procedural macro.</li>
</ol>
</main>
</body>
Expand Down
8 changes: 2 additions & 6 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,6 @@ pub struct Variable {
pub identifier: Identifier,
/// The index operation e.g. `[1]` in `x[1]`.
pub index: Option<Box<Offset>>,
/// The cast e.g. `:i32` in `x:i32`.
pub cast: Option<Cast>,
}

impl From<Identifier> for Variable {
Expand All @@ -311,7 +309,6 @@ impl From<Identifier> for Variable {
addressing: Addressing::Direct,
identifier,
index: None,
cast: None,
}
}
}
Expand All @@ -322,7 +319,6 @@ impl From<&[char]> for Variable {
addressing: Addressing::Direct,
identifier: Identifier::from(chars),
index: None,
cast: None,
}
}
}
Expand Down Expand Up @@ -488,7 +484,7 @@ pub enum Type {
Array(Box<Array>),
Reference(Box<Type>),
TypeType,
Boolean
Boolean,
}

impl Default for Type {
Expand Down Expand Up @@ -542,7 +538,7 @@ impl std::fmt::Display for Type {
Array(array) => write!(f, "{array}"),
Reference(reference) => write!(f, "&{reference}"),
TypeType => write!(f, "type"),
Boolean => write!(f,"bool")
Boolean => write!(f, "bool"),
}
}
}
Expand Down
195 changes: 99 additions & 96 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ mod macros;

mod parsing;

mod backend;
use backend::*;
// mod backend;

mod exploration;
// mod exploration;

mod inlining;

mod temporary_intrinsics;

mod optimization;

mod including;
Expand Down Expand Up @@ -157,6 +158,10 @@ fn build(path: Option<PathBuf>) {

// Inlines functions
let inlined = unsafe { inlining::inline_functions(nodes) };

// Convert `loop`s and `if`s to inline assembly.
let inlined = unsafe { temporary_intrinsics::inline(nodes) };

let inlined_string = display_ast(inlined);
write_file(
&project_path,
Expand All @@ -165,8 +170,6 @@ fn build(path: Option<PathBuf>) {
&mut lock_file,
);

// Convert `loop`s and `if`s to inline assembly.

// Pre-exploration optimizations
unsafe { optimization::prex_optimization(inlined) }
let prex_optimization_string = display_ast(inlined);
Expand All @@ -177,27 +180,27 @@ fn build(path: Option<PathBuf>) {
&mut lock_file,
);

// Explore variable space.
let mut explorer = unsafe { exploration::Explorer::new(inlined) };
let mut i = 0;
let explored = loop {
explorer = match unsafe { explorer.next() } {
exploration::ExplorationResult::Continue(e) => e,
exploration::ExplorationResult::Done(e) => break e,
};

i += 1;
assert!(i < 50);
};
let explored_string = display_ast(explored);
write_file(
&project_path,
PathBuf::from("explored").with_extension(LANGUAGE_EXTENSION),
explored_string.as_bytes(),
&mut lock_file,
);
// // Explore variable space.
// let mut explorer = unsafe { exploration::Explorer::new(inlined) };
// let mut i = 0;
// let explored = loop {
// explorer = match unsafe { explorer.next() } {
// exploration::ExplorationResult::Continue(e) => e,
// exploration::ExplorationResult::Done(e) => break e,
// };

// i += 1;
// assert!(i < 50);
// };
// let explored_string = display_ast(explored);
// write_file(
// &project_path,
// PathBuf::from("explored").with_extension(LANGUAGE_EXTENSION),
// explored_string.as_bytes(),
// &mut lock_file,
// );

// Optimize source
// // Optimize source
// let optimized = unsafe { optimize(explored) };
// let optimized_string = display_ast(optimized);
// write_file(
Expand All @@ -207,78 +210,78 @@ fn build(path: Option<PathBuf>) {
// &mut lock_file,
// );

// Construct assembly
let assembly = assembly_from_node(explored);
let assembly_path = PathBuf::from("assembly").with_extension("s");
write_file(
&project_path,
assembly_path.clone(),
assembly.as_bytes(),
&mut lock_file,
);
// // Construct assembly
// let assembly = assembly_from_node(explored);
// let assembly_path = PathBuf::from("assembly").with_extension("s");
// write_file(
// &project_path,
// assembly_path.clone(),
// assembly.as_bytes(),
// &mut lock_file,
// );

// Make object file
let object_path = project_path.join("build").join("object").with_extension("o");
let object_output = std::process::Command::new("as")
.args([
"-o",
&object_path.display().to_string(),
&project_path.join("build").join(assembly_path).display().to_string(),
])
.output()
.unwrap();
assert_eq!(
object_output.stdout,
[],
"{}",
std::str::from_utf8(&object_output.stdout).unwrap()
);
assert_eq!(
object_output.stderr,
[],
"{}",
std::str::from_utf8(&object_output.stderr).unwrap()
);
assert_eq!(object_output.status.code(), Some(0));
// Write object hash
let mut object_buffer = Vec::new();
let mut object_file = OpenOptions::new().read(true).open(&object_path).unwrap();
object_file.read_to_end(&mut object_buffer).unwrap();
let object_hash = HEXUPPER.encode(sha256_digest(object_buffer.as_slice()).unwrap().as_ref());
let object_file_name = object_path.file_stem().unwrap();
writeln!(&mut lock_file, "{},{object_hash}", object_file_name.to_str().unwrap()).unwrap();

// Make binary file
let binary_path = project_path.join("build").join("binary");
let binary_output = std::process::Command::new("ld")
.args([
"-s",
"-o",
&binary_path.display().to_string(),
&object_path.display().to_string(),
])
.output()
.unwrap();
assert_eq!(
binary_output.stdout,
[],
"{}",
std::str::from_utf8(&binary_output.stdout).unwrap()
);
assert_eq!(
binary_output.stderr,
[],
"{}",
std::str::from_utf8(&binary_output.stderr).unwrap()
);
assert_eq!(binary_output.status.code(), Some(0));
// Write binary hash
let mut binary_buffer = Vec::new();
let mut binary_file = OpenOptions::new().read(true).open(&binary_path).unwrap();
binary_file.read_to_end(&mut binary_buffer).unwrap();
let binary_hash = HEXUPPER.encode(sha256_digest(binary_buffer.as_slice()).unwrap().as_ref());
let binary_file_name = binary_path.file_stem().unwrap();
writeln!(&mut lock_file, "{},{binary_hash}", binary_file_name.to_str().unwrap()).unwrap();
// // Make object file
// let object_path = project_path.join("build").join("object").with_extension("o");
// let object_output = std::process::Command::new("as")
// .args([
// "-o",
// &object_path.display().to_string(),
// &project_path.join("build").join(assembly_path).display().to_string(),
// ])
// .output()
// .unwrap();
// assert_eq!(
// object_output.stdout,
// [],
// "{}",
// std::str::from_utf8(&object_output.stdout).unwrap()
// );
// assert_eq!(
// object_output.stderr,
// [],
// "{}",
// std::str::from_utf8(&object_output.stderr).unwrap()
// );
// assert_eq!(object_output.status.code(), Some(0));
// // Write object hash
// let mut object_buffer = Vec::new();
// let mut object_file = OpenOptions::new().read(true).open(&object_path).unwrap();
// object_file.read_to_end(&mut object_buffer).unwrap();
// let object_hash = HEXUPPER.encode(sha256_digest(object_buffer.as_slice()).unwrap().as_ref());
// let object_file_name = object_path.file_stem().unwrap();
// writeln!(&mut lock_file, "{},{object_hash}", object_file_name.to_str().unwrap()).unwrap();

// // Make binary file
// let binary_path = project_path.join("build").join("binary");
// let binary_output = std::process::Command::new("ld")
// .args([
// "-s",
// "-o",
// &binary_path.display().to_string(),
// &object_path.display().to_string(),
// ])
// .output()
// .unwrap();
// assert_eq!(
// binary_output.stdout,
// [],
// "{}",
// std::str::from_utf8(&binary_output.stdout).unwrap()
// );
// assert_eq!(
// binary_output.stderr,
// [],
// "{}",
// std::str::from_utf8(&binary_output.stderr).unwrap()
// );
// assert_eq!(binary_output.status.code(), Some(0));
// // Write binary hash
// let mut binary_buffer = Vec::new();
// let mut binary_file = OpenOptions::new().read(true).open(&binary_path).unwrap();
// binary_file.read_to_end(&mut binary_buffer).unwrap();
// let binary_hash = HEXUPPER.encode(sha256_digest(binary_buffer.as_slice()).unwrap().as_ref());
// let binary_file_name = binary_path.file_stem().unwrap();
// writeln!(&mut lock_file, "{},{binary_hash}", binary_file_name.to_str().unwrap()).unwrap();
}

fn run(path: Option<PathBuf>) {
Expand Down
39 changes: 20 additions & 19 deletions src/optimization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,26 @@ use std::ptr::NonNull;

// Pre-exploration optimization.
pub unsafe fn prex_optimization(root: NonNull<AstNode>) {
let mut stack = vec![root];
while let Some(mut current) = stack.pop() {
match current.as_ref().statement.op {
Op::Unreachable => {
assert_eq!(current.as_ref().child, None);
if let Some(next) = current.as_ref().next {
crate::exploration::dealloc_ast(next);
}
}
_ => {
if let Some(child) = current.as_ref().child {
stack.push(child);
}
if let Some(next) = current.as_ref().next {
stack.push(next);
}
}
}
}
// let mut stack = vec![root];
// while let Some(mut current) = stack.pop() {
// match current.as_ref().statement.op {
// Op::Unreachable => {
// assert_eq!(current.as_ref().child, None);
// if let Some(next) = current.as_ref().next {
// crate::exploration::dealloc_ast(next);
// }
// }
// _ => {
// if let Some(child) = current.as_ref().child {
// stack.push(child);
// }
// if let Some(next) = current.as_ref().next {
// stack.push(next);
// }
// }
// }
// }
todo!()
}

/// Post-exploration optimization.
Expand Down
Loading

0 comments on commit 8ed22c2

Please sign in to comment.