├── .gitattributes ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE.md ├── README.md ├── build.rs ├── examples ├── fibonacci.lc ├── main.lc └── structures.lc ├── rust-toolchain ├── specification.md ├── src ├── analysis │ ├── function.rs │ ├── loops.rs │ └── mod.rs ├── arena.rs ├── binary │ ├── compile.rs │ ├── entry.rs │ ├── format │ │ ├── mach │ │ │ ├── command.rs │ │ │ ├── compile.rs │ │ │ ├── mod.rs │ │ │ └── segment.rs │ │ └── mod.rs │ ├── mod.rs │ └── patch.rs ├── context.rs ├── error.rs ├── generate │ ├── mod.rs │ ├── section.rs │ └── x86 │ │ ├── binary.rs │ │ ├── call.rs │ │ ├── cast.rs │ │ ├── function.rs │ │ ├── lower.rs │ │ ├── mod.rs │ │ ├── node.rs │ │ ├── register.rs │ │ ├── target.rs │ │ └── value.rs ├── inference │ ├── context.rs │ ├── mod.rs │ ├── path.rs │ ├── scene.rs │ ├── structure.rs │ └── value.rs ├── main.rs ├── node │ ├── address.rs │ ├── context.rs │ ├── function.rs │ ├── item.rs │ ├── mod.rs │ ├── offsets.rs │ ├── position.rs │ └── present.rs ├── other.rs ├── parse │ ├── function.rs │ ├── item.rs │ ├── mod.rs │ ├── symbols.rs │ └── value.rs ├── query │ ├── key.rs │ ├── mod.rs │ └── table.rs └── span.rs └── tree-sitter-lucent ├── README.md ├── binding.gyp ├── grammar.js ├── index.js ├── package.json ├── queries └── highlights.scm ├── src ├── binding.cc ├── grammar.json ├── node-types.json ├── parser.c ├── scanner.c └── tree_sitter │ └── parser.h ├── test └── corpus │ ├── expressions.txt │ └── items.txt └── yarn.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | tree-sitter-lucent/src/parser.c linguist-generated 2 | tree-sitter-lucent/src/binding.cc linguist-generated 3 | tree-sitter-lucent/src/grammar.json linguist-generated 4 | tree-sitter-lucent/src/node-types.json linguist-generated 5 | tree-sitter-lucent/src/tree_sitter/parser.h linguist-generated 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea 3 | node_modules 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lucent" 3 | version = "0.1.0" 4 | authors = ["Technocoder <8334328+Techno-coder@users.noreply.github.com>"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | tree-sitter = "^0.16" 9 | parking_lot = "^0.10" 10 | codespan-reporting = "^0.9" 11 | codespan = "^0.9" 12 | dashmap = "^3.0" 13 | indexmap = "^1.4" 14 | goblin = "^0.2" 15 | 16 | [dependencies.scroll] 17 | version = "^0.10" 18 | features = ["derive"] 19 | 20 | [dependencies.iced-x86] 21 | version = "^1.2" 22 | default-features = false 23 | features = [ 24 | "std", 25 | "nasm", 26 | "block_encoder", 27 | "db", 28 | ] 29 | 30 | [build-dependencies] 31 | cc = "*" 32 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Technocoder (Techno-coder) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lucent 2 | 3 | A transparent systems language for linking and development on freestanding and embedded environments. 4 | 5 | ``` 6 | @@binary "flat" 7 | @load 1024 * 1024 8 | @architecture "x32" 9 | module Loader 10 | module Header 11 | static MAGIC: u32 = 0xe85250d6 12 | static ARCHITECTURE: u32 = 0 13 | static HEADER_LENGTH: u32 = 14 | Intrinsic.size(Header) as u32 15 | static CHECK: u32 = 0x100000000 - 16 | (0xe85250d6 + HEADER_LENGTH) 17 | 18 | module EndTag 19 | static TYPE: u16 = 0 20 | static FLAGS: u16 = 0 21 | static SIZE: u32 = 8 22 | 23 | module Main 24 | root fn start() 25 | $esp = Intrinsic.end(STACK) 26 | check_multiboot() 27 | 28 | fn check_multiboot() 29 | if $eax != 0x36d76289: 30 | no_multiboot(0) 31 | 32 | fn no_multiboot(code: u8) never 33 | *(0xb8000 as *u32) = 0x4f524f45 34 | *(0xb8004 as *u32) = 0x4f3a4f52 35 | *(0xb8008 as *u32) = 0x4f204f20 36 | *(0xb800a as *u32) = code 37 | inline x86.halt() 38 | 39 | static STACK: [u8; 64 * 1024] 40 | ``` 41 | 42 | ## Planned features 43 | * Minimal code optimizations 44 | * Fast and incremental compilation 45 | * Arbitrary compile time evaluation 46 | * Embed bytes directly into functions 47 | * Ergonomic import of symbols from binary files 48 | 49 | ## Design 50 | The Lucent language's core philosophy is **transparency**. Transparency (in this context) means that it should be easy to understand how the source code transforms into the final binary output. To that extent, all optimizations (or lack thereof) are a part of the language's [specification](specification.md). 51 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | fn main() { 4 | let path: PathBuf = ["tree-sitter-lucent", "src"].iter().collect(); 5 | cc::Build::new().include(&path).file(path.join("parser.c")) 6 | .file(path.join("scanner.c")).compile("tree-sitter-lucent"); 7 | } 8 | -------------------------------------------------------------------------------- /examples/fibonacci.lc: -------------------------------------------------------------------------------- 1 | @@binary "mach-o" 2 | @@entry Intrinsic.start(Main.main) 3 | 4 | @architecture "x64" 5 | @load 1024 * 1024 6 | module Main 7 | root fn main() u8 8 | (fibonacci(46) % 100) as u8 9 | 10 | fn fibonacci(n: u64) u64 11 | let i = 0 12 | let a = 0 13 | let b = 1 14 | while i < n: 15 | let c = a + b 16 | a = b 17 | b = c 18 | i += 1 19 | return b 20 | 21 | fn fibonacci'(n: u64) u64 22 | if n <= 1: return 1 23 | fibonacci'(n - 1) + fibonacci'(n - 2) 24 | -------------------------------------------------------------------------------- /examples/main.lc: -------------------------------------------------------------------------------- 1 | @@binary "flat" 2 | @load 1024 * 1024 3 | @architecture "x32" 4 | module Loader 5 | module Header 6 | static MAGIC: u32 = 0xe85250d6 7 | static ARCHITECTURE: u32 = 0 8 | static HEADER_LENGTH: u32 = 9 | Intrinsic.size(Header) as u32 10 | static CHECK: u32 = 0x100000000 - 11 | (0xe85250d6 + HEADER_LENGTH) 12 | 13 | module EndTag 14 | static Type: u16 = 0 15 | static Flags: u16 = 0 16 | static Size: u32 = 8 17 | 18 | module Main 19 | root fn start() 20 | $esp = Intrinsic.end(STACK) 21 | check_multiboot() 22 | 23 | fn check_multiboot() 24 | if $eax != 0x36d76289: 25 | no_multiboot(0) 26 | 27 | fn no_multiboot(code: u8) never 28 | *(0xb8000 as *u32) = 0x4f524f45 29 | *(0xb8004 as *u32) = 0x4f3a4f52 30 | *(0xb8008 as *u32) = 0x4f204f20 31 | *(0xb800a as *u32) = code 32 | // inline x86.halt() 33 | while true: true 34 | 35 | static STACK: [u8; 64 * 1024] 36 | -------------------------------------------------------------------------------- /examples/structures.lc: -------------------------------------------------------------------------------- 1 | @@binary "mach-o" 2 | @@entry Intrinsic.start(Main.main) 3 | 4 | @architecture "x64" 5 | @load 1024 * 1024 6 | module Main 7 | data Pair 8 | a: u8 9 | b: u8 10 | 11 | root fn main() u8 12 | pair(Pair ~ a = 1, b = 2).b 13 | 14 | fn pair(pair: Pair) Pair 15 | Pair ~ a = pair.a, b = pair.b 16 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | nightly 2 | -------------------------------------------------------------------------------- /specification.md: -------------------------------------------------------------------------------- 1 | # [Prototype] Lucent Language Reference 2 | 3 | ## Comments 4 | Comment lines are prefixed with `//`: 5 | ``` 6 | // This is a comment 7 | ``` 8 | 9 | ## Identifiers 10 | Identifiers are a sequence of unicode characters. 11 | 12 | They cannot: 13 | * Begin with a digit 14 | * Begin with the prime character: `'` 15 | * Contain punctuation characters other than underscores: `_` and primes: `'` 16 | 17 | These are examples of valid identifiers: 18 | ``` 19 | variable 20 | variable' 21 | a_variable 22 | variable_ 23 | _unused 24 | a'123 25 | 😄 26 | ``` 27 | 28 | These are not valid identifiers: 29 | ``` 30 | 'prime 31 | 0digit 32 | a)b 33 | ``` 34 | 35 | ## Variables 36 | ``` 37 | let identifier: type = value 38 | ``` 39 | The type can be omitted if it can be inferred: 40 | ``` 41 | let identifier = value 42 | ``` 43 | The variable can also be default initialized to zero: 44 | ``` 45 | let identifier 46 | ``` 47 | 48 | ### Shadowing 49 | Variables declared with existing names shadow the previous variables: 50 | ``` 51 | let a: u32 = 0 52 | let a: u32 = 1 53 | // a == 1 54 | ``` 55 | 56 | ## Literals 57 | ### Integral 58 | Integrals are composed of a series of digits. The digits can be prefixed to change the base: 59 | * Hexadecimal: `0x` 60 | * Binary: `0b` 61 | * Octal: `0o` 62 | 63 | Literals can be separated with primes: `'`. 64 | 65 | ### Rune 66 | ``` 67 | 'rune' 68 | ``` 69 | Character or literals are enclosed within a pair of single quotes. 70 | 71 | ### Registers 72 | ``` 73 | $register 74 | ``` 75 | Register literals are prefixed with the `$` character. Registers can be assigned to and read from. 76 | 77 | ## Primitive types 78 | ``` 79 | rune 80 | truth 81 | never 82 | void 83 | ``` 84 | ### Integral types 85 | ``` 86 | u8 87 | u16 88 | u32 89 | u64 90 | i8 91 | i16 92 | i32 93 | i64 94 | ``` 95 | If the type of an integer is ambiguous then it is assumed to be the smallest signed type that fits the value. 96 | 97 | ## Pointer type 98 | ``` 99 | *type 100 | ``` 101 | Pointer types are constructed by prefixing a type by an asterisk. The size of a pointer is dependent on the contextual architecture. Pointers can be constructed by taking the address of a variable with an ampersand: 102 | ``` 103 | let variable: i32 = 0 104 | let pointer: *i32 = &variable 105 | ``` 106 | Addition and subtraction can be performed on pointers with any integer type: 107 | ``` 108 | let pointer: *i32 = &variable + 1 109 | ``` 110 | The offset is dependent on the size of the pointed type. 111 | 112 | ## Conversions 113 | ``` 114 | value as type 115 | ``` 116 | ### Integral 117 | * Conversions between integral types of the same width will not change the bit representation 118 | * Reductions in width will take the lower (least significant) bits 119 | * Increases in width sign extend the bit representation 120 | 121 | ### Integral to truth 122 | * `0` is defined as `false` 123 | * Any other number is defined as `true` 124 | 125 | ### [Future] Pointer to pointer 126 | ``` 127 | pointer as *type 128 | ``` 129 | Pointers can be casted to any other pointer including function pointers: 130 | ``` 131 | pointer as convention fn(type) type 132 | ``` 133 | 134 | ## Static variables 135 | ``` 136 | static identifier: type = value 137 | ``` 138 | Static variables can be default initialized to zero: 139 | ``` 140 | static identifier: type 141 | ``` 142 | The type of a static variable can be omitted if the value is specified: 143 | ``` 144 | static identifier = value 145 | ``` 146 | Values assigned to a static variable are evaluated at compilation time. 147 | 148 | ## If expressions 149 | ``` 150 | if condition: 151 | statement.0 152 | statement.1 153 | ... 154 | ``` 155 | If expressions can only have a single branch. Branches with a single statement can be collapsed into a single line: 156 | ``` 157 | if condition: statement.0 158 | ``` 159 | 160 | ## When expressions 161 | When expressions are similar to if expressions. Multiple branches are collated under a single expression: 162 | ``` 163 | when: 164 | condition.0: 165 | statement.0 166 | ... 167 | condition.1: 168 | statement.1 169 | ... 170 | ... 171 | true: 172 | ... 173 | ``` 174 | 175 | If no branch exists with a `true` condition then the type of the expression is `void`. Otherwise, it is the type of the expression in each branch. 176 | 177 | ## While loops 178 | ``` 179 | while condition: 180 | statement.0 181 | ... 182 | ``` 183 | Loops with a single statement can be collapsed into a single line: 184 | ``` 185 | while condition: statement.0 186 | ``` 187 | 188 | ## Functions 189 | ``` 190 | fn identifier(parameter.0: type.0, ...) type.return 191 | statement.0 192 | statement.1 193 | ... 194 | expression 195 | ``` 196 | Functions can also be defined on one line: 197 | ``` 198 | fn identifier(...) type.return = expression 199 | ``` 200 | The return type can be omitted if it is void: 201 | ``` 202 | fn identifier(...) = expression 203 | ``` 204 | Calling conventions can also be specified: 205 | ``` 206 | convention identifier(...) = expression 207 | ``` 208 | Marking a function as `root` will prevent the function from being removed from the final binary: 209 | ``` 210 | root identifier(...) = expression 211 | ``` 212 | 213 | ### Register parameters 214 | ``` 215 | fn identifier($register.0, $register.1, ...) type.return = ... 216 | ``` 217 | Registers may also be used as a parameter. The same register cannot appear twice. Calling code will move the parameters into the target registers before invocation. 218 | 219 | ## Sequence types 220 | Arrays and slices have an element type. 221 | 222 | ### Arrays 223 | ``` 224 | let identifier: [type; number] = [value.0, value.1, ...] 225 | ``` 226 | Fixed size arrays must have the number of elements in the type. 227 | 228 | ### Slices 229 | ``` 230 | let identifier: [type;] = array[start:end] 231 | ``` 232 | Slices are constructed from slicing an array. They can also be created from an address and size: 233 | ``` 234 | let identifier = [type;] address, size 235 | ``` 236 | 237 | ## Compilation time execution 238 | ``` 239 | let identifier = #expression 240 | ``` 241 | Prefixing an expression with `#` will evaluate it at compilation time. 242 | 243 | ## Inline values 244 | ``` 245 | inline value 246 | ``` 247 | Inline values are inserted into the function at the inline location. 248 | 249 | ### Inline byte sequences 250 | ``` 251 | inline [byte.0, byte.1, ...] 252 | ``` 253 | The contents of the byte sequence is spliced into the function body at compilation time. 254 | 255 | ### [Future] Inline nodes 256 | ``` 257 | inline node 258 | ``` 259 | The node is directly copied into the function body at the point of inlining. 260 | 261 | ## Modules 262 | ``` 263 | module identifier 264 | ... 265 | ``` 266 | Modules contains functions and global symbols. 267 | 268 | ## Structures 269 | ``` 270 | data identifier 271 | field.0: type.0 272 | field.1: type.1 273 | ... 274 | ``` 275 | Structures are constructed by initialization: 276 | ``` 277 | identifier ~ field.0 = value.0, field.1 = value.1, ... 278 | ``` 279 | If there are variables in scope with the same name as the field then the assignment can be omitted: 280 | ``` 281 | let field.0 = value.0 282 | identifier ~ field.0, ... 283 | ``` 284 | Fields omitted from the construction are default initialized to zero. 285 | 286 | ### [Future] Structure variants 287 | Structures can also have variants: 288 | ``` 289 | data identifier 290 | ... 291 | variant.0(type.0a, type.0b, ...) 292 | variant.1(type.1a, type.1b, ...) 293 | ... 294 | ``` 295 | These variants can be destructured with a `match` expression. 296 | 297 | ## Annotations 298 | ``` 299 | @annotation.0 parameter 300 | @annotation.1 parameter 301 | item 302 | ``` 303 | Annotations affect the subsequent item. 304 | Global annotations affect the entire compilation unit and can only be declared in the root file. 305 | ``` 306 | @@annotation parameter 307 | ``` 308 | Annotation parameters can be any expression that can be evaluated at compilation time. 309 | 310 | ### Binary 311 | Binary annotations describe the values that used in the headers of the output binary files. 312 | 313 | * Type: `@@type` 314 | * Architecture: `@@architecture` 315 | * Entry point: `@@entry` 316 | 317 | ### Architecture 318 | ``` 319 | @architecture identifier 320 | item 321 | ``` 322 | Architectures specify how intrinsic language structures should be translated including call and control flow instructions. This annotation can only be applied to modules and functions. 323 | 324 | ### Addresses 325 | Address annotations change the location of a symbol in memory. They can be overridden by annotations in nested items. Annotations on modules offset all the items in the module by the same address. 326 | 327 | ``` 328 | @load address 329 | item 330 | ``` 331 | The `load` annotation sets where the item is to be loaded into memory. Specifically, it sets the memory address where the loader should copy the binary contents. This also sets the virtual address for the item. 332 | 333 | ``` 334 | @virtual address 335 | item 336 | ``` 337 | The `virtual` annotation defines what other instructions should treat the address as. For example, call instructions will invoke the virtual address instead of the actual (load) address. 338 | 339 | ### Admissions 340 | Admissions are compiler warnings or notes. They can be suppressed by annotating the offending item: 341 | ``` 342 | @admit identifier 343 | item 344 | ``` 345 | 346 | ## Libraries 347 | ``` 348 | use "path" as identifier 349 | ``` 350 | Libraries can be imported as a namespaced name. Symbols from the library must be explicitly imported: 351 | ``` 352 | use identifier.function as fn function(type.0, ...) 353 | ``` 354 | Addresses from the library can be directly imported: 355 | ``` 356 | use identifier.address as fn function(type.0, ...) 357 | ``` 358 | Calling conventions can be specified on the function signature: 359 | ``` 360 | use identifier.function as convention fn(type.0, ...) 361 | ``` 362 | Symbols can also be imported as static variables: 363 | ``` 364 | use identifier.symbol as variable: type 365 | ``` 366 | ### [Removed] Implicit symbol names 367 | Named symbols can have the import name omitted: 368 | ``` 369 | use identifier.function as fn(type.0, ...) 370 | ``` 371 | 372 | ### Address annotations 373 | ``` 374 | @load address.0 375 | @virtual address.1 376 | use "path" as identifier 377 | ``` 378 | Libraries may be relocated with address annotations but if the library type does not support relocation then an admission will be issued. 379 | 380 | ### [Future] C interoperability 381 | ``` 382 | use "path" with "path.h" 383 | ``` 384 | Symbols can be read automatically from a C header file. They can also be namespaced: 385 | ``` 386 | use "path" with "path.h" as identifier 387 | ``` 388 | 389 | ## File management 390 | ``` 391 | use "./path.lc" 392 | ``` 393 | Other source files can be included at the place of usage. Source inclusions can also be namespaced: 394 | ``` 395 | use "./path.lc" as identifier 396 | ``` 397 | 398 | ## Namespace management 399 | ``` 400 | use path 401 | use path as identifier 402 | use path.* 403 | ``` 404 | Namespace imports are effective after the position of import and only within the enclosing scope. Wildcards are allowed only as the last element in the path. 405 | 406 | ## Guarantees 407 | ### Function pruning 408 | Any function not directly or indirectly called by a root function will be removed from the final binary. More strictly, functions that are not called will not attempt to be translated. This includes library functions (where possible) and functions that are only invoked at compilation time. 409 | 410 | ### Symbol pruning 411 | Static variables will never be removed from the final binary. 412 | 413 | ## Verification 414 | ### Address overlaps 415 | Addresses and regions are checked at compilation time to ensure no region overlaps with each other. 416 | 417 | ## Behaviour 418 | ### Register allocation 419 | Registers explicitly used will never be used by the register allocator. If a used register conflicts with a required register (such as the parameter of a calling convention) then the contents will be moved into an unused register or otherwise spilled to stack. 420 | -------------------------------------------------------------------------------- /src/analysis/function.rs: -------------------------------------------------------------------------------- 1 | use crate::context::Context; 2 | use crate::node::{Function, FunctionPath}; 3 | use crate::query::Key; 4 | use crate::span::Span; 5 | 6 | pub fn function(context: &Context, parent: Option, path: &FunctionPath, 7 | function: &Function, span: Option) -> crate::Result<()> { 8 | let key = Key::Analyze(path.clone()); 9 | context.unit.scope(parent, key, span, || 10 | super::loops(context, function)).map(std::mem::drop) 11 | } 12 | -------------------------------------------------------------------------------- /src/analysis/loops.rs: -------------------------------------------------------------------------------- 1 | use crate::context::Context; 2 | use crate::error::Diagnostic; 3 | use crate::node::{Function, Value, ValueIndex, ValueNode}; 4 | 5 | /// Verifies break and continue statements 6 | /// are enclosed within a loop. 7 | pub fn loops(context: &Context, function: &Function) -> crate::Result<()> { 8 | value(context, &function.value, &function.value.root, false) 9 | } 10 | 11 | fn value(context: &Context, value: &Value, index: &ValueIndex, 12 | state: bool) -> crate::Result<()> { 13 | let span = &value[*index].span; 14 | Ok(match &value[*index].node { 15 | ValueNode::Block(values) => values.iter() 16 | .map(|index| self::value(context, value, index, state)) 17 | .filter(Result::is_err).last().unwrap_or(Ok(()))?, 18 | ValueNode::Let(_, _, Some(index)) => 19 | self::value(context, value, index, state)?, 20 | ValueNode::Set(target, index) => { 21 | self::value(context, value, target, state)?; 22 | self::value(context, value, index, state)?; 23 | } 24 | ValueNode::While(condition, index) => { 25 | self::value(context, value, condition, state)?; 26 | self::value(context, value, index, true)?; 27 | } 28 | ValueNode::When(branches) => 29 | branches.iter().map(|(condition, index)| { 30 | self::value(context, value, index, state)?; 31 | self::value(context, value, condition, state) 32 | }).filter(Result::is_err).last().unwrap_or(Ok(()))?, 33 | ValueNode::Cast(index, _) | 34 | ValueNode::Return(Some(index)) | 35 | ValueNode::Compile(index) | 36 | ValueNode::Inline(index) => 37 | self::value(context, value, index, true)?, 38 | ValueNode::Call(_, arguments) => arguments.iter() 39 | .map(|index| self::value(context, value, index, state)) 40 | .filter(Result::is_err).last().unwrap_or(Ok(()))?, 41 | ValueNode::Field(index, _) => 42 | self::value(context, value, index, true)?, 43 | ValueNode::Create(_, fields) => fields.values() 44 | .map(|(index, _)| self::value(context, value, index, state)) 45 | .filter(Result::is_err).last().unwrap_or(Ok(()))?, 46 | ValueNode::Slice(index, start, end) => { 47 | self::value(context, value, index, state)?; 48 | start.iter().try_for_each(|start| 49 | self::value(context, value, start, state))?; 50 | end.iter().try_for_each(|end| 51 | self::value(context, value, end, state))? 52 | } 53 | ValueNode::Index(node, index) => { 54 | self::value(context, value, node, state)?; 55 | self::value(context, value, index, state)?; 56 | } 57 | ValueNode::Compound(_, target, index) => { 58 | self::value(context, value, target, state)?; 59 | self::value(context, value, index, state)?; 60 | } 61 | ValueNode::Binary(_, left, right) => { 62 | self::value(context, value, left, state)?; 63 | self::value(context, value, right, state)?; 64 | } 65 | ValueNode::Unary(_, index) => 66 | self::value(context, value, index, state)?, 67 | ValueNode::Continue if !state => return context 68 | .pass(Diagnostic::error().label(span.label()) 69 | .message("continue not enclosed in loop")), 70 | ValueNode::Break if !state => return context 71 | .pass(Diagnostic::error().label(span.label()) 72 | .message("break not enclosed in loop")), 73 | _ => (), 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /src/analysis/mod.rs: -------------------------------------------------------------------------------- 1 | //! Passes for verifying parsed items. 2 | //! Analysis occurs before type inference so no 3 | //! pass may use type information for verification. 4 | 5 | pub use function::*; 6 | pub use loops::*; 7 | 8 | mod function; 9 | mod loops; 10 | -------------------------------------------------------------------------------- /src/arena.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | type ArenaNode = Option>>; 4 | 5 | #[derive(Debug)] 6 | struct Node(T, ArenaNode); 7 | 8 | #[derive(Debug)] 9 | pub struct OwnedArena<'a, T> { 10 | _owner: PhantomData<&'a ()>, 11 | root: ArenaNode, 12 | } 13 | 14 | impl<'a, T> OwnedArena<'a, T> { 15 | pub fn push(&mut self, value: T) -> &'a mut T { 16 | self.root = Some(Box::new(Node(value, self.root.take()))); 17 | let Node(value, _) = self.root.as_mut().unwrap().as_mut(); 18 | unsafe { (value as *mut T).as_mut() }.unwrap() 19 | } 20 | } 21 | 22 | impl<'a, T> Default for OwnedArena<'a, T> { 23 | fn default() -> Self { 24 | OwnedArena { 25 | _owner: Default::default(), 26 | root: None, 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/binary/compile.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::Write; 3 | 4 | use crate::context::Context; 5 | use crate::error::Diagnostic; 6 | 7 | pub fn compile(context: &Context) -> crate::Result<()> { 8 | // TODO: derive from global annotation 9 | let path = "binary.bin"; 10 | 11 | // TODO: verify no overlaps 12 | let mut entries = super::entries(context); 13 | super::patch(context, &mut entries); 14 | if crate::context::failed(context) { 15 | return Err(crate::query::QueryError::Failure); 16 | } 17 | 18 | let segments = super::segments(entries); 19 | for segment in &segments { 20 | match &segment.kind { 21 | super::SegmentKind::Text(data) => { 22 | for byte in data.iter().flatten() { 23 | print!("{:02x} ", byte); 24 | } 25 | println!(); 26 | } 27 | _ => (), 28 | } 29 | } 30 | 31 | // TODO: derive format from global annotation 32 | let data = super::format::mach::compile(segments); 33 | 34 | let data = data.map_err(|error| context.error(Diagnostic::error() 35 | .message("failed to compile binary").note(format!("error: {}", error))))?; 36 | File::create(path).and_then(|mut file| file.write_all(&data)) 37 | .map_err(|error| context.error(Diagnostic::error() 38 | .message("failed to write binary to file") 39 | .note(format!("error: {}", error)))) 40 | } 41 | -------------------------------------------------------------------------------- /src/binary/entry.rs: -------------------------------------------------------------------------------- 1 | use crate::context::Context; 2 | use crate::generate::Section; 3 | use crate::node::{Item, Symbol}; 4 | use crate::node::address::{Address, SymbolSize}; 5 | 6 | #[derive(Debug)] 7 | pub struct Entry { 8 | pub load: Address, 9 | pub address: Address, 10 | pub size: SymbolSize, 11 | pub entity: Entity, 12 | } 13 | 14 | #[derive(Debug)] 15 | pub enum Entity { 16 | Function(Section), 17 | Variable(Option>), 18 | } 19 | 20 | #[derive(Debug)] 21 | pub struct Segment { 22 | pub address: Address, 23 | pub kind: SegmentKind, 24 | } 25 | 26 | #[derive(Debug)] 27 | pub enum SegmentKind { 28 | Text(Vec>), 29 | Data(Vec>), 30 | Reserve(usize), 31 | } 32 | 33 | pub fn entries(context: &Context) -> Vec { 34 | let mut entries = Vec::new(); 35 | context.items.read().iter().for_each(|item| 36 | std::mem::drop(entry(context, &mut entries, item))); 37 | entries 38 | } 39 | 40 | fn entry(context: &Context, entries: &mut Vec, 41 | item: &Item) -> crate::Result<()> { 42 | match item { 43 | Item::Symbol(symbol @ Symbol::Function(path)) => { 44 | if !crate::node::present(context, None, path, None)? { return Ok(()); } 45 | let section = crate::generate::x86::lower(context, None, path, None)?; 46 | let address = crate::node::address::start(context, None, symbol, None)?; 47 | let load = crate::node::address::load(context, None, symbol, None)?; 48 | let size = crate::node::address::size(context, None, symbol, None)?; 49 | let entity = Entity::Function(section.as_ref().clone()); 50 | Ok(entries.push(Entry { load, address, size, entity })) 51 | } 52 | Item::Symbol(Symbol::Variable(_)) => unimplemented!(), 53 | Item::Symbol(Symbol::Module(_)) => Ok(()), 54 | Item::ModuleEnd => Ok(()), 55 | } 56 | } 57 | 58 | pub fn segments(mut entries: Vec) -> Vec { 59 | let mut segments = Vec::new(); 60 | let segment: &mut Option = &mut None; 61 | let mut last_address: Option
= None; 62 | 63 | entries.sort_unstable_by_key(|entry| entry.load); 64 | for Entry { load: address, size, entity, .. } in entries { 65 | let kind = segment.as_mut().map(|segment| &mut segment.kind); 66 | let push = &mut |segment: &mut Option, kind| { 67 | if let Some(segment) = segment.take() { segments.push(segment); } 68 | *segment = Some(Segment { address, kind }); 69 | }; 70 | 71 | match entity { 72 | Entity::Function(section) => match kind { 73 | Some(SegmentKind::Text(sections)) if last_address == 74 | Some(address) => sections.push(section.bytes), 75 | _ => push(segment, SegmentKind::Text(vec![section.bytes])) 76 | }, 77 | Entity::Variable(Some(other)) => match kind { 78 | Some(SegmentKind::Data(data)) if last_address == 79 | Some(address) => data.push(other), 80 | _ => push(segment, SegmentKind::Data(vec![other])), 81 | }, 82 | Entity::Variable(None) => match kind { 83 | Some(SegmentKind::Reserve(reserve)) if last_address == 84 | Some(address) => *reserve += size, 85 | _ => push(segment, SegmentKind::Reserve(size)), 86 | } 87 | } 88 | 89 | last_address = Some(address + size); 90 | } 91 | 92 | segments.extend(segment.take()); 93 | segments 94 | } 95 | -------------------------------------------------------------------------------- /src/binary/format/mach/command.rs: -------------------------------------------------------------------------------- 1 | use std::io::{self, Cursor}; 2 | 3 | use goblin::mach::{constants, load_command}; 4 | use scroll::{IOwrite, Pwrite, SizeWith}; 5 | 6 | use super::{BinarySegment, PAGE_SIZE}; 7 | 8 | #[repr(C)] 9 | #[derive(Debug, Pwrite, IOwrite, SizeWith)] 10 | pub struct UnixThreadCommand { 11 | command: u32, 12 | command_size: u32, 13 | flavor: u32, 14 | count: u32, 15 | thread_state: [u64; 21], 16 | } 17 | 18 | impl UnixThreadCommand { 19 | const STATE_COUNT: usize = 21; 20 | 21 | pub fn new(instruction_address: u64) -> Self { 22 | use std::mem::size_of; 23 | const X86_THREAD_STATE64: u32 = 4; 24 | const STATE_SIZE: usize = size_of::<[u64; UnixThreadCommand::STATE_COUNT]>(); 25 | const STATE_COUNT: usize = STATE_SIZE / size_of::(); 26 | 27 | const INSTRUCTION_REGISTER: usize = 16; 28 | let mut thread_state = [0; Self::STATE_COUNT]; 29 | thread_state[INSTRUCTION_REGISTER] = instruction_address; 30 | 31 | UnixThreadCommand { 32 | command: load_command::LC_UNIXTHREAD, 33 | command_size: size_of::() as u32, 34 | flavor: X86_THREAD_STATE64, 35 | count: STATE_COUNT as u32, 36 | thread_state, 37 | } 38 | } 39 | } 40 | 41 | #[derive(Debug)] 42 | pub struct LoadCommands { 43 | pub zero: load_command::SegmentCommand64, 44 | pub header: load_command::SegmentCommand64, 45 | pub segments: Vec, 46 | pub thread: UnixThreadCommand, 47 | } 48 | 49 | impl LoadCommands { 50 | pub fn new(segments: Vec, thread: UnixThreadCommand) -> Self { 51 | let zero = BinarySegment::default().name(b"__PAGEZERO").size(PAGE_SIZE as u64).build(); 52 | let header = BinarySegment::default().name(b"__TEXT").address(PAGE_SIZE as u64) 53 | .protections(constants::VM_PROT_EXECUTE | constants::VM_PROT_READ).build(); 54 | LoadCommands { zero, header, segments, thread } 55 | } 56 | 57 | pub fn size_count(&self) -> (u32, usize) { 58 | std::iter::once(self.zero.cmdsize) 59 | .chain(std::iter::once(self.header.cmdsize)) 60 | .chain(std::iter::once(self.thread.command_size)) 61 | .chain(self.segments.iter().map(|command| command.cmdsize)) 62 | .fold((0, 0), |(size, count), command_size| (size + command_size, count + 1)) 63 | } 64 | 65 | pub fn write(self, target: &mut Cursor>) -> io::Result<()> { 66 | Iterator::chain(std::array::IntoIter::new([self.zero, self.header]), 67 | self.segments).try_for_each(|segment| target.iowrite(segment))?; 68 | target.iowrite(self.thread) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/binary/format/mach/compile.rs: -------------------------------------------------------------------------------- 1 | use std::io::{self, Cursor, Write}; 2 | 3 | use goblin::mach::{constants, header, load_command}; 4 | use scroll::IOwrite; 5 | 6 | use crate::binary::{Segment, SegmentKind}; 7 | use crate::other::ceiling; 8 | 9 | use super::{BinarySegment, LoadCommands, UnixThreadCommand}; 10 | 11 | // TODO: derive from architecture 12 | pub const PAGE_SIZE: usize = 4096; 13 | 14 | pub fn compile(segments: Vec) -> io::Result> { 15 | let entry = 1024 * 1024; // TODO: derive from annotation 16 | let thread = UnixThreadCommand::new(entry); 17 | let binary_segments = self::segments(&segments); 18 | let mut commands = LoadCommands::new(binary_segments, thread); 19 | let (size, command_count) = commands.size_count(); 20 | 21 | let mut bytes = Vec::new(); 22 | let mut offset = header::SIZEOF_HEADER_64 + size as usize; 23 | commands.header.filesize = offset as u64; 24 | commands.header.vmsize = offset as u64; 25 | 26 | let command_segments = commands.segments.iter_mut(); 27 | let iterator = Iterator::zip(segments.into_iter(), command_segments); 28 | for (segment, binary_segment) in iterator { 29 | fill_page(&mut offset, &mut bytes); 30 | binary_segment.fileoff = offset as u64; 31 | 32 | match segment.kind { 33 | SegmentKind::Text(data) | SegmentKind::Data(data) => data 34 | .into_iter().try_for_each(|data| bytes.write(&data) 35 | .map(|bytes| offset += bytes))?, 36 | SegmentKind::Reserve(_) => (), 37 | } 38 | } 39 | 40 | fill_page(&mut offset, &mut bytes); 41 | let mut target = Cursor::new(Vec::new()); 42 | target.iowrite(header::Header { 43 | magic: header::MH_MAGIC_64, 44 | cputype: constants::cputype::CPU_TYPE_X86_64, 45 | cpusubtype: constants::cputype::CPU_SUBTYPE_X86_64_ALL, 46 | filetype: header::MH_EXECUTE, 47 | ncmds: command_count, 48 | sizeofcmds: size, 49 | flags: header::MH_NOUNDEFS, 50 | reserved: 0, 51 | })?; 52 | 53 | commands.write(&mut target)?; 54 | target.write_all(&bytes)?; 55 | Ok(target.into_inner()) 56 | } 57 | 58 | fn fill_page(offset: &mut usize, bytes: &mut Vec) { 59 | let padding = ceiling(*offset, PAGE_SIZE) - *offset; 60 | bytes.resize(bytes.len() + padding, 0); 61 | *offset += padding; 62 | } 63 | 64 | fn segments(segments: &[Segment]) -> Vec { 65 | segments.iter().map(|segment| match &segment.kind { 66 | SegmentKind::Text(data) => { 67 | let size = data.iter().map(Vec::len).sum::() as u64; 68 | BinarySegment::default().name(b"__TEXT") 69 | .address(segment.address as u64).size(size).file_size(size) 70 | .protections(constants::VM_PROT_EXECUTE | constants::VM_PROT_READ) 71 | } 72 | SegmentKind::Data(data) => { 73 | let size = data.iter().map(Vec::len).sum::() as u64; 74 | BinarySegment::default().name(b"__DATA") 75 | .address(segment.address as u64).size(size).file_size(size) 76 | .protections(constants::VM_PROT_READ | constants::VM_PROT_WRITE) 77 | } 78 | SegmentKind::Reserve(size) => BinarySegment::default().name(b"__DATA") 79 | .address(segment.address as u64).size(*size as u64).file_size(0) 80 | .protections(constants::VM_PROT_READ | constants::VM_PROT_WRITE), 81 | }.build()).collect() 82 | } 83 | -------------------------------------------------------------------------------- /src/binary/format/mach/mod.rs: -------------------------------------------------------------------------------- 1 | pub use command::*; 2 | pub use compile::*; 3 | pub use segment::*; 4 | 5 | mod compile; 6 | mod segment; 7 | mod command; -------------------------------------------------------------------------------- /src/binary/format/mach/segment.rs: -------------------------------------------------------------------------------- 1 | use goblin::mach::load_command; 2 | 3 | #[derive(Debug, Default)] 4 | pub struct BinarySegment { 5 | name: [u8; 16], 6 | address: u64, 7 | size: u64, 8 | offset: u64, 9 | file_size: u64, 10 | protections: u32, 11 | } 12 | 13 | impl BinarySegment { 14 | pub fn name(mut self, name: &[u8]) -> Self { 15 | self.name[..name.len()].copy_from_slice(name); 16 | self 17 | } 18 | 19 | pub fn address(mut self, address: u64) -> Self { 20 | self.address = address; 21 | self 22 | } 23 | 24 | pub fn size(mut self, size: u64) -> Self { 25 | self.size = size; 26 | self 27 | } 28 | 29 | pub fn file_size(mut self, file_size: u64) -> Self { 30 | self.file_size = file_size; 31 | self 32 | } 33 | 34 | pub fn protections(mut self, protection: u32) -> Self { 35 | self.protections |= protection; 36 | self 37 | } 38 | 39 | pub fn build(self) -> load_command::SegmentCommand64 { 40 | load_command::SegmentCommand64 { 41 | cmd: load_command::LC_SEGMENT_64, 42 | cmdsize: load_command::SIZEOF_SEGMENT_COMMAND_64 as u32, 43 | segname: self.name, 44 | vmaddr: self.address, 45 | vmsize: self.size, 46 | fileoff: self.offset, 47 | filesize: self.file_size, 48 | maxprot: self.protections, 49 | initprot: self.protections, 50 | nsects: 0, 51 | flags: 0, 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/binary/format/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod mach; 2 | -------------------------------------------------------------------------------- /src/binary/mod.rs: -------------------------------------------------------------------------------- 1 | pub use compile::*; 2 | pub use entry::*; 3 | pub use patch::*; 4 | 5 | pub mod format; 6 | 7 | mod compile; 8 | mod entry; 9 | mod patch; 10 | -------------------------------------------------------------------------------- /src/binary/patch.rs: -------------------------------------------------------------------------------- 1 | use crate::context::Context; 2 | use crate::generate::Relative; 3 | use crate::node::{Size, Symbol}; 4 | use crate::node::address::Address; 5 | 6 | use super::{Entity, Entry}; 7 | 8 | pub fn patch(context: &Context, entries: &mut [Entry]) { 9 | entries.iter_mut().map(|entry| entity(context, 10 | &mut entry.entity, &entry.address)).for_each(std::mem::drop) 11 | } 12 | 13 | fn entity(context: &Context, entity: &mut Entity, 14 | address: &Address) -> crate::Result<()> { 15 | Ok(match entity { 16 | Entity::Function(section) => { 17 | for Relative { size, offset, target, path } in §ion.relative { 18 | let symbol = Symbol::Function(path.clone()); 19 | let other = crate::node::address::start(context, None, &symbol, None)?; 20 | let slice = &mut section.bytes[*offset..*offset + size.bytes()]; 21 | let relative = other as isize - (*address + *target) as isize; 22 | 23 | match size { 24 | Size::Byte => slice.copy_from_slice(&(relative as i8).to_le_bytes()), 25 | Size::Word => slice.copy_from_slice(&(relative as i16).to_le_bytes()), 26 | Size::Double => slice.copy_from_slice(&(relative as i32).to_le_bytes()), 27 | Size::Quad => slice.copy_from_slice(&(relative as i64).to_le_bytes()), 28 | } 29 | } 30 | } 31 | Entity::Variable(_) => (), 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /src/context.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{HashMap, HashSet}; 2 | use std::io::Read; 3 | use std::path::PathBuf; 4 | use std::sync::Arc; 5 | 6 | use codespan::FileId; 7 | use dashmap::DashMap; 8 | use parking_lot::{Mutex, RwLock}; 9 | 10 | use crate::error::Diagnostic; 11 | use crate::generate::Section; 12 | use crate::inference::Types; 13 | use crate::node::*; 14 | use crate::query::{QueryError, Table}; 15 | use crate::span::Span; 16 | 17 | #[derive(Debug, Default)] 18 | pub struct Context { 19 | pub unit: Table<()>, 20 | pub files: RwLock, 21 | pub items: RwLock>, 22 | pub modules: DashMap, 23 | pub statics: DashMap, 24 | pub structures: DashMap, 25 | pub functions: DashMap>>, 26 | pub positions: RwLock>, 27 | pub present: RwLock>, 28 | pub type_contexts: Table, 29 | pub sections: Table
, 30 | pub offsets: Table, 31 | pub address: Table, 32 | diagnostics: Mutex>, 33 | } 34 | 35 | impl Context { 36 | pub fn error(&self, diagnostic: Diagnostic) -> QueryError { 37 | self.diagnostics.lock().push(diagnostic); 38 | QueryError::Failure 39 | } 40 | 41 | pub fn pass(&self, diagnostic: Diagnostic) -> crate::Result { 42 | Err(self.error(diagnostic)) 43 | } 44 | 45 | pub fn emit(&self, diagnostic: Diagnostic) { 46 | let _ = self.pass::(diagnostic); 47 | } 48 | } 49 | 50 | #[derive(Debug)] 51 | pub struct Files { 52 | files: codespan::Files>, 53 | paths: HashMap, 54 | pub internal: Span, 55 | } 56 | 57 | impl Files { 58 | pub fn query(&mut self, path: &std::path::Path) -> Option<(FileId, Arc)> { 59 | match self.paths.get(path) { 60 | Some(file) => Some((file.clone(), self.files.source(*file).clone())), 61 | None => { 62 | let mut string = String::new(); 63 | let mut file = std::fs::File::open(path).ok()?; 64 | file.read_to_string(&mut string).ok()?; 65 | 66 | let file = self.files.add(path.file_name().unwrap(), string.into()); 67 | self.paths.insert(path.to_owned(), file); 68 | Some((file, self.files.source(file).clone())) 69 | } 70 | } 71 | } 72 | } 73 | 74 | impl Default for Files { 75 | fn default() -> Self { 76 | let paths = HashMap::new(); 77 | let mut files = codespan::Files::new(); 78 | let file = files.add("", "".into()); 79 | let start = files.source_span(file).start().to_usize(); 80 | let end = files.source_span(file).end().to_usize(); 81 | let internal = Span::new(start..end, file); 82 | Files { files, paths, internal } 83 | } 84 | } 85 | 86 | pub fn failed(context: &Context) -> bool { 87 | context.diagnostics.lock().iter() 88 | .any(|Diagnostic(diagnostic)| diagnostic.severity == 89 | codespan_reporting::diagnostic::Severity::Error) 90 | } 91 | 92 | pub fn display(context: &Context) -> std::io::Result<()> { 93 | use codespan_reporting::term; 94 | let files = &context.files.read().files; 95 | let configuration = &term::Config::default(); 96 | let colors = term::termcolor::ColorChoice::Auto; 97 | let writer = &mut term::termcolor::StandardStream::stderr(colors); 98 | context.diagnostics.lock().iter().try_for_each(|Diagnostic(diagnostic)| 99 | term::emit(writer, configuration, files, diagnostic)) 100 | } 101 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use codespan::FileId; 2 | use codespan_reporting::diagnostic; 3 | 4 | #[derive(Debug)] 5 | pub struct Diagnostic(pub diagnostic::Diagnostic); 6 | 7 | impl Diagnostic { 8 | pub fn error() -> Self { 9 | Self(diagnostic::Diagnostic::error()) 10 | } 11 | 12 | pub fn message(mut self, message: impl Into) -> Self { 13 | let Self(diagnostic) = &mut self; 14 | diagnostic.message = message.into(); 15 | self 16 | } 17 | 18 | pub fn label(mut self, label: diagnostic::Label) -> Self { 19 | let Self(diagnostic) = &mut self; 20 | diagnostic.labels.push(label); 21 | self 22 | } 23 | 24 | pub fn note(mut self, note: impl Into) -> Self { 25 | let Self(diagnostic) = &mut self; 26 | diagnostic.notes.push(note.into()); 27 | self 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/generate/mod.rs: -------------------------------------------------------------------------------- 1 | pub use section::*; 2 | 3 | mod section; 4 | pub mod x86; 5 | -------------------------------------------------------------------------------- /src/generate/section.rs: -------------------------------------------------------------------------------- 1 | use crate::node::{FunctionPath, Size}; 2 | 3 | pub type Offset = usize; 4 | 5 | #[derive(Debug, Default, Clone)] 6 | pub struct Section { 7 | pub bytes: Vec, 8 | // TODO: replace with compile time execution nodes 9 | pub relative: Vec, 10 | } 11 | 12 | #[derive(Debug, Clone)] 13 | pub struct Relative { 14 | pub size: Size, 15 | pub offset: Offset, 16 | pub target: Offset, 17 | pub path: FunctionPath, 18 | } 19 | -------------------------------------------------------------------------------- /src/generate/x86/binary.rs: -------------------------------------------------------------------------------- 1 | use iced_x86::{Code, Register}; 2 | use iced_x86::Instruction as I; 3 | 4 | use crate::context::Context; 5 | use crate::inference::Types; 6 | use crate::node::{Binary, Compare, Dual, Size, Type, Value, ValueIndex}; 7 | use crate::span::Span; 8 | 9 | use super::{Scene, Translation}; 10 | 11 | macro_rules! integer_dual { 12 | ($type:expr, $left:ident, $right: ident) => { 13 | match $type { 14 | Type::Signed(size) => code_rm!(size, $left, $right), 15 | Type::Unsigned(size) => code_rm!(size, $left, $right), 16 | other => panic!("invalid arithmetic type: {}", other), 17 | } 18 | }; 19 | } 20 | 21 | macro_rules! binary_dual { 22 | ($type:expr, $left:ident, $right: ident) => {{ 23 | use Code::*; 24 | match $type { 25 | Type::Truth => concat_idents!($left, r8, $right, m8), 26 | Type::Signed(size) => code_rm!(size, $left, $right), 27 | Type::Unsigned(size) => code_rm!(size, $left, $right), 28 | other => panic!("invalid arithmetic type: {}", other), 29 | } 30 | }}; 31 | } 32 | 33 | pub fn binary(context: &Context, scene: &mut Scene, prime: &mut Translation, 34 | types: &Types, value: &Value, binary: &Binary, left: &ValueIndex, 35 | right: &ValueIndex, span: &Span) -> crate::Result<()> { 36 | if matches!(binary, Binary::Or) || matches!(binary, Binary::And) { 37 | return short(context, scene, prime, types, value, binary, left, right, span); 38 | } 39 | 40 | super::value(context, scene, prime, types, value, left)?; 41 | let size = super::size(context, scene, &types[left], span)?; 42 | let (register, alternate) = (scene.primary[size], scene.alternate[size]); 43 | let stack = super::size(context, scene, &types[left], span).map(super::stack)?; 44 | let stack_primary = scene.primary[stack]; 45 | 46 | define_note!(note, prime, span); 47 | note(I::with_reg(super::code_push(stack), stack_primary)); 48 | std::mem::swap(&mut scene.primary, &mut scene.alternate); 49 | super::value(context, scene, prime, types, value, right)?; 50 | 51 | define_note!(note, prime, span); 52 | std::mem::swap(&mut scene.primary, &mut scene.alternate); 53 | note(I::with_reg(super::code_pop(stack), stack_primary)); 54 | 55 | Ok(match binary { 56 | Binary::Or | Binary::And => unreachable!(), 57 | Binary::Compare(compare) => { 58 | note(I::with_reg_reg(code_rm!(size, 59 | Cmp_, _r), register, alternate)); 60 | note(I::with_reg(match compare { 61 | Compare::Less => Code::Setl_rm8, 62 | Compare::Greater => Code::Setg_rm8, 63 | Compare::LessEqual => Code::Setle_rm8, 64 | Compare::GreaterEqual => Code::Setge_rm8, 65 | Compare::NotEqual => Code::Setne_rm8, 66 | Compare::Equal => Code::Sete_rm8, 67 | }, scene.primary[Size::Byte])); 68 | } 69 | Binary::Dual(Dual::Multiply) => match size { 70 | Size::Byte => super::reserve(scene, prime, Register::AL, |scene, prime| { 71 | super::convey(scene, prime, alternate, Register::BL, |_, prime, other| { 72 | super::transfer(prime, register, Register::AL, size, span); 73 | prime.push(I::with_reg(Code::Imul_rm8, other), span); 74 | }, size, span); 75 | super::transfer(prime, Register::AL, register, size, span); 76 | }, size, span), 77 | other => note(I::with_reg_reg(match other { 78 | Size::Byte => unreachable!(), 79 | Size::Word => Code::Imul_r16_rm16, 80 | Size::Double => Code::Imul_r32_rm32, 81 | Size::Quad => Code::Imul_r64_rm64, 82 | }, register, alternate)), 83 | }, 84 | Binary::Dual(dual @ Dual::Divide) | 85 | Binary::Dual(dual @ Dual::Modulo) => { 86 | let (target, clear) = (register!(size, A), register!(size, D)); 87 | super::reserve(scene, prime, target, |scene, prime| { 88 | super::reserve(scene, prime, clear, |scene, prime| { 89 | super::convey(scene, prime, alternate, 90 | register!(size, B), |_, prime, other| { 91 | super::transfer(prime, register, target, size, span); 92 | define_note!(note, prime, span); 93 | match &types[left] { 94 | Type::Signed(size) => { 95 | note(I::with(super::code_sign_extend(*size))); 96 | note(I::with_reg(code_m!(size, Idiv_r), other)); 97 | } 98 | Type::Unsigned(size) => { 99 | let code = code_rm!(size, Xor_, _r); 100 | note(I::with_reg_reg(code, clear, clear)); 101 | note(I::with_reg(code_m!(size, Div_r), other)); 102 | } 103 | other => panic!("invalid arithmetic type: {}", other), 104 | } 105 | }, size, span); 106 | super::transfer(prime, match dual { 107 | Dual::Divide => register!(size, A), 108 | Dual::Modulo => register!(size, D), 109 | _ => unreachable!(), 110 | }, register, size, span); 111 | }, size, span) 112 | }, size, span) 113 | } 114 | Binary::Dual(dual @ Dual::ShiftLeft) | 115 | Binary::Dual(dual @ Dual::ShiftRight) => 116 | super::reserve(scene, prime, Register::CL, |scene, prime| { 117 | super::convey(scene, prime, register, 118 | register!(size, A), |scene, prime, other| { 119 | let alternate = scene.alternate[Size::Byte]; 120 | super::transfer(prime, alternate, Register::CL, Size::Byte, span); 121 | prime.push(I::with_reg_reg(match (dual, &types[left]) { 122 | (Dual::ShiftLeft, Type::Signed(size)) => code_m!(size, Sal_r, _CL), 123 | (Dual::ShiftLeft, Type::Unsigned(size)) => code_m!(size, Shl_r, _CL), 124 | (Dual::ShiftRight, Type::Signed(size)) => code_m!(size, Sar_r, _CL), 125 | (Dual::ShiftRight, Type::Unsigned(size)) => code_m!(size, Shr_r, _CL), 126 | (_, other) => panic!("invalid arithmetic type: {}", other), 127 | }, other, Register::CL), span); 128 | super::transfer(prime, other, register, size, span); 129 | }, size, span); 130 | }, size, span), 131 | Binary::Dual(dual) => { 132 | if let Type::Pointer(path) = &types[left] { 133 | let scale = crate::node::size(context, scene 134 | .parent.clone(), &path.node, Some(span.clone()))?; 135 | return super::scale_index(scene, prime, 136 | &types[right], scale, *dual, span); 137 | } 138 | 139 | note(I::with_reg_reg(match dual { 140 | Dual::Add => integer_dual!(&types[left], Add_, _r), 141 | Dual::Minus => integer_dual!(&types[left], Sub_, _r), 142 | Dual::Divide | Dual::Modulo | Dual::Multiply => unreachable!(), 143 | Dual::ShiftLeft | Dual::ShiftRight => unreachable!(), 144 | Dual::BinaryOr => binary_dual!(&types[left], Or_, _r), 145 | Dual::BinaryAnd => binary_dual!(&types[left], And_, _r), 146 | Dual::ExclusiveOr => binary_dual!(&types[left], Xor_, _r), 147 | }, register, alternate)); 148 | } 149 | }) 150 | } 151 | 152 | fn short(context: &Context, scene: &mut Scene, prime: &mut Translation, 153 | types: &Types, value: &Value, binary: &Binary, left: &ValueIndex, 154 | right: &ValueIndex, span: &Span) -> crate::Result<()> { 155 | super::value(context, scene, prime, types, value, left)?; 156 | define_note!(note, prime, span); 157 | let register = scene.primary[Size::Byte]; 158 | note(I::with_reg_reg(Code::Test_rm8_r8, register, register)); 159 | 160 | let exit = scene.label(); 161 | note(I::with_branch(match binary { 162 | Binary::Or => relative!(scene.mode, Jne), 163 | Binary::And => relative!(scene.mode, Je), 164 | _ => unreachable!(), 165 | }, exit)); 166 | 167 | super::value(context, scene, prime, types, value, right)?; 168 | Ok(prime.set_pending_label(exit, span)) 169 | } 170 | -------------------------------------------------------------------------------- /src/generate/x86/call.rs: -------------------------------------------------------------------------------- 1 | use iced_x86::Code; 2 | use iced_x86::Instruction as I; 3 | use iced_x86::MemoryOperand as M; 4 | 5 | use crate::context::Context; 6 | use crate::inference::Types; 7 | use crate::node::{FunctionPath, Path, Size, Type, Value, ValueIndex}; 8 | use crate::span::{S, Span}; 9 | 10 | use super::{Mode, Scene, Translation}; 11 | 12 | pub fn call(context: &Context, scene: &mut Scene, prime: &mut Translation, 13 | types: &Types, value: &Value, index: &ValueIndex, path: &S, 14 | arguments: &[ValueIndex], span: &Span) -> crate::Result<()> { 15 | let reserved: Vec<_> = scene.reserved.iter().cloned().collect(); 16 | reserved.iter().rev().for_each(|registers| 17 | prime.push(I::with_reg(super::code_push(scene.mode.size()), 18 | registers[scene.mode.size()]), span)); 19 | 20 | // TODO: move and return registers 21 | let mut size = arguments.iter().rev().try_fold(0, |size, argument| { 22 | super::value(context, scene, prime, types, value, argument)?; 23 | if types[argument].composite() { 24 | let stack = crate::node::size(context, scene.parent 25 | .clone(), &types[argument], Some(span.clone()))?; 26 | super::stack_reserve(scene, prime, stack, span); 27 | let memory = M::with_base(scene.mode.stack()); 28 | super::set(scene, prime, &types[argument], stack, 29 | memory, scene.mode_primary(), span); 30 | Ok(size + stack) 31 | } else { 32 | let stack = super::size(context, scene, 33 | &types[argument], span).map(super::stack)?; 34 | prime.push(I::with_reg(super::code_push(stack), 35 | scene.primary[stack]), span); 36 | Ok(size + stack.bytes()) 37 | } 38 | })? as i32; 39 | 40 | let mut composite = None; 41 | if types[index].composite() { 42 | size += scene.mode.size().bytes() as i32; 43 | let size = crate::node::size(context, scene.parent 44 | .clone(), &types[index], Some(span.clone()))?; 45 | let offset = *composite.get_or_insert(scene.reserve(size)); 46 | 47 | define_note!(note, prime, span); 48 | let memory = M::with_base_displ(scene.mode.base(), offset as i32); 49 | note(I::with_reg_mem(super::load(scene.mode), scene.mode_primary(), memory)); 50 | note(I::with_reg(super::code_push(scene.mode.size()), scene.mode_primary())); 51 | } 52 | 53 | let call_index = prime.instructions.len(); 54 | let path = FunctionPath(path.node.clone(), types.functions[index]); 55 | prime.calls.push((call_index, path)); 56 | 57 | define_note!(note, prime, span); 58 | note(I::with_branch(relative!(scene.mode, Call), 0)); 59 | note(I::with_reg_i32(match scene.mode { 60 | Mode::Protected => Code::Add_rm32_imm32, 61 | Mode::Long => Code::Add_rm64_imm32, 62 | Mode::Real => Code::Add_rm16_imm16, 63 | }, scene.mode.stack(), size)); 64 | 65 | // TODO: calling convention dependent 66 | if let Some(offset) = composite { 67 | let memory = M::with_base_displ(scene.mode.base(), offset as i32); 68 | prime.push(I::with_reg_mem(super::load(scene.mode), 69 | scene.mode_primary(), memory), span); 70 | } else if !matches!(types[index], Type::Void | Type::Never) { 71 | let size = super::size(context, scene, &types[index], span)?; 72 | let (register, target) = (register!(size, A), scene.primary[size]); 73 | super::transfer(prime, register, target, size, span); 74 | } 75 | 76 | Ok(reserved.iter().for_each(|registers| 77 | prime.push(I::with_reg(super::code_pop(scene.mode.size()), 78 | registers[scene.mode.size()]), span))) 79 | } 80 | -------------------------------------------------------------------------------- /src/generate/x86/cast.rs: -------------------------------------------------------------------------------- 1 | use iced_x86::Code; 2 | use iced_x86::Instruction as I; 3 | 4 | use crate::context::Context; 5 | use crate::error::Diagnostic; 6 | use crate::inference::Types; 7 | use crate::node::{Size, Type, Value, ValueIndex}; 8 | use crate::span::{S, Span}; 9 | 10 | use super::{Scene, Translation}; 11 | 12 | pub fn cast(context: &Context, scene: &mut Scene, prime: &mut Translation, 13 | types: &Types, value: &Value, index: &ValueIndex, target: &S, 14 | span: &Span) -> crate::Result<()> { 15 | super::value(context, scene, prime, types, value, index)?; 16 | define_note!(note, prime, span); 17 | Ok(match (&types[index], &target.node) { 18 | (Type::Signed(size), Type::Signed(target)) | 19 | (Type::Signed(size), Type::Unsigned(target)) => 20 | sign_extend(scene, *size, *target) 21 | .into_iter().for_each(note), 22 | (Type::Unsigned(size), Type::Signed(target)) | 23 | (Type::Unsigned(size), Type::Unsigned(target)) => 24 | zero_extend(scene, *size, *target) 25 | .into_iter().for_each(note), 26 | // TODO: other casts 27 | (path, node) => return context.pass(Diagnostic::error() 28 | .label(span.label().with_message(path.to_string())) 29 | .label(target.span.label().with_message(node.to_string())) 30 | .message("cannot cast types")), 31 | }) 32 | } 33 | 34 | pub fn zero_extend(scene: &Scene, size: Size, target: Size) -> Option { 35 | Some(I::with_reg_reg(match (size, target) { 36 | (Size::Byte, Size::Word) => Code::Movzx_r16_rm8, 37 | (Size::Byte, Size::Double) => Code::Movzx_r32_rm8, 38 | (Size::Byte, Size::Quad) => Code::Movzx_r64_rm8, 39 | (Size::Word, Size::Double) => Code::Movzx_r32_rm16, 40 | (Size::Word, Size::Quad) => Code::Movzx_r64_rm16, 41 | _ => return None, 42 | }, scene.primary[target], scene.primary[size])) 43 | } 44 | 45 | pub fn sign_extend(scene: &Scene, size: Size, target: Size) -> Option { 46 | Some(I::with_reg_reg(match (size, target) { 47 | (Size::Byte, Size::Word) => Code::Movsx_r16_rm8, 48 | (Size::Byte, Size::Double) => Code::Movsx_r32_rm8, 49 | (Size::Byte, Size::Quad) => Code::Movsx_r64_rm8, 50 | (Size::Word, Size::Double) => Code::Movsx_r32_rm16, 51 | (Size::Word, Size::Quad) => Code::Movsx_r64_rm16, 52 | (Size::Double, Size::Quad) => Code::Movsxd_r64_rm32, 53 | _ => return None, 54 | }, scene.primary[target], scene.primary[size])) 55 | } 56 | -------------------------------------------------------------------------------- /src/generate/x86/function.rs: -------------------------------------------------------------------------------- 1 | use iced_x86::{Code, Register}; 2 | use iced_x86::Instruction as I; 3 | use iced_x86::MemoryOperand as M; 4 | 5 | use crate::context::Context; 6 | use crate::inference::Types; 7 | use crate::node::{Function, Parameter, ReturnType, Size, Type, Value, ValueIndex}; 8 | use crate::span::Span; 9 | 10 | use super::{Mode, Scene, Translation}; 11 | 12 | pub fn entry(scene: &Scene, prime: &mut Translation, internal: &Span) { 13 | let (size, base) = (scene.mode.size(), scene.mode.base()); 14 | prime.push(I::with_reg(super::code_push(size), base), internal); 15 | super::transfer(prime, scene.mode.stack(), base, size, internal); 16 | stack_reserve(scene, prime, 0, internal); 17 | } 18 | 19 | pub fn render(context: &Context, scene: &mut Scene, prime: &mut Translation, 20 | types: &Types, value: &Value, index: Option, 21 | span: &Span) -> crate::Result<()> { 22 | if let Some(index) = index { 23 | // TODO: calling convention dependent 24 | super::value(context, scene, prime, types, value, &index)?; 25 | match &types[&index] { 26 | Type::Void => (), 27 | Type::Never => return Ok(()), 28 | path if path.composite() => { 29 | let size = crate::node::size(context, 30 | scene.parent.clone(), path, Some(span.clone()))?; 31 | let offset = scene.parameters_offset() as i32; 32 | let memory = M::with_base_displ(scene.mode.base(), offset); 33 | 34 | region(scene, prime, |scene, prime, registers| { 35 | let (source, counter, target) = registers; 36 | super::transfer(prime, scene.mode_primary(), 37 | source, scene.mode.size(), span); 38 | define_note!(note, prime, span); 39 | let code = code_rm!(scene.mode.size(), Mov_, _r); 40 | note(I::with_reg_mem(code, target, memory)); 41 | let code = code_rm!(scene.mode.size(), Mov_, _im); 42 | note(I::with_reg_i32(code, counter, size as i32)); 43 | note(I::with_rep_movsb(scene.mode.size() as u32)); 44 | }, span); 45 | } 46 | path => { 47 | let size = super::size(context, scene, path, span)?; 48 | let (register, target) = (scene.primary[size], register!(size, A)); 49 | super::transfer(prime, register, target, size, span); 50 | } 51 | } 52 | } 53 | 54 | define_note!(note, prime, span); 55 | note(I::with(match scene.mode { 56 | Mode::Protected => Code::Leaved, 57 | Mode::Long => Code::Leaveq, 58 | Mode::Real => Code::Leavew, 59 | })); 60 | 61 | Ok(note(I::with(match scene.mode { 62 | Mode::Protected => Code::Retnd, 63 | Mode::Long => Code::Retnq, 64 | Mode::Real => Code::Retnw, 65 | }))) 66 | } 67 | 68 | // TODO: calling convention dependent 69 | pub fn parameters(context: &Context, function: &Function, 70 | scene: &mut Scene) -> crate::Result<()> { 71 | let mut offset = scene.parameters_offset(); 72 | if let ReturnType::Type(path) = &function.return_type.node { 73 | if path.node.composite() { offset += scene.mode.size().bytes(); } 74 | } 75 | 76 | Ok(for parameter in &function.parameters { 77 | if let Parameter::Variable(variable, path) = ¶meter.node { 78 | scene.variables.insert(variable.node.clone(), offset as isize); 79 | let size = crate::node::size(context, scene.parent.clone(), 80 | &path.node, Some(variable.span.clone()))?; 81 | offset += if size == 1 { 2 } else { size } 82 | } 83 | }) 84 | } 85 | 86 | pub fn stack_reserve(scene: &Scene, prime: &mut Translation, 87 | size: usize, span: &Span) { 88 | prime.push(I::with_reg_i32(match scene.mode { 89 | Mode::Protected => Code::Sub_rm32_imm32, 90 | Mode::Long => Code::Sub_rm64_imm32, 91 | Mode::Real => Code::Sub_rm16_imm16, 92 | }, scene.mode.stack(), size as i32), span); 93 | } 94 | 95 | pub fn zero(scene: &mut Scene, prime: &mut Translation, 96 | offset: isize, size: usize, span: &Span) { 97 | let target = scene.mode.destination(); 98 | let counter = register!(scene.mode.size(), C); 99 | super::reserve(scene, prime, counter, |scene, prime| { 100 | super::reserve(scene, prime, target, |scene, prime| { 101 | super::reserve(scene, prime, Register::AL, |scene, prime| { 102 | define_note!(note, prime, span); 103 | let memory = M::with_base_displ(scene.mode.base(), offset as i32); 104 | note(I::with_reg_reg(Code::Xor_r8_rm8, Register::AL, Register::AL)); 105 | 106 | let code = code_rm!(scene.mode.size(), Mov_, _im); 107 | note(I::with_reg_i32(code, counter, size as i32)); 108 | note(I::with_reg_mem(super::load(scene.mode), target, memory)); 109 | note(I::with_rep_stosb(scene.mode.size() as u32)); 110 | }, Size::Byte, span); 111 | }, Size::Byte, span); 112 | }, Size::Byte, span); 113 | } 114 | 115 | pub fn set(scene: &mut Scene, prime: &mut Translation, path: &Type, 116 | size: usize, mut memory: M, register: Register, span: &Span) { 117 | memory.displ_size = 1; 118 | match path.composite() { 119 | false => prime.push(I::with_mem_reg(match path { 120 | Type::Truth => Code::Mov_rm8_r8, 121 | Type::Rune => Code::Mov_rm32_r32, 122 | Type::Pointer(_) => Code::Mov_rm64_r64, 123 | Type::Signed(size) | Type::Unsigned(size) => match size { 124 | Size::Byte => Code::Mov_rm8_r8, 125 | Size::Word => Code::Mov_rm16_r16, 126 | Size::Double => Code::Mov_rm32_r32, 127 | Size::Quad => Code::Mov_rm64_r64, 128 | }, 129 | Type::Slice(_) | Type::Array(_, _) | Type::Structure(_) 130 | | Type::Void | Type::Never => unreachable!(), 131 | }, memory, register), span), 132 | true => region(scene, prime, |scene, prime, registers| { 133 | let (source, counter, target) = registers; 134 | let default = register!(scene.mode.size(), A); 135 | super::convey(scene, prime, register, default, |scene, prime, register| { 136 | prime.push(I::with_reg_mem(super::load(scene.mode), target, memory), span); 137 | super::transfer(prime, register, source, scene.mode.size(), span); 138 | 139 | define_note!(note, prime, span); 140 | let code = code_rm!(scene.mode.size(), Mov_, _im); 141 | note(I::with_reg_i32(code, counter, size as i32)); 142 | note(I::with_rep_movsb(scene.mode.size() as u32)); 143 | }, scene.mode.size(), span) 144 | }, span), 145 | } 146 | } 147 | 148 | fn region(scene: &mut Scene, prime: &mut Translation, function: F, span: &Span) 149 | where F: FnOnce(&mut Scene, &mut Translation, (Register, Register, Register)) { 150 | let target = scene.mode.destination(); 151 | let counter = register!(scene.mode.size(), C); 152 | let source = match scene.mode { 153 | Mode::Protected => Register::ESI, 154 | Mode::Long => Register::RSI, 155 | Mode::Real => Register::SI, 156 | }; 157 | 158 | super::reserve(scene, prime, source, |scene, prime| { 159 | super::reserve(scene, prime, counter, |scene, prime| { 160 | super::reserve(scene, prime, target, |scene, prime| { 161 | function(scene, prime, (source, counter, target)); 162 | }, scene.mode.size(), span); 163 | }, scene.mode.size(), span); 164 | }, scene.mode.size(), span); 165 | } 166 | -------------------------------------------------------------------------------- /src/generate/x86/lower.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{HashMap, HashSet}; 2 | use std::sync::Arc; 3 | 4 | use iced_x86::{BlockEncoder, BlockEncoderOptions, Instruction, InstructionBlock}; 5 | 6 | use crate::context::Context; 7 | use crate::generate::{Relative, Section}; 8 | use crate::node::{FunctionPath, Size, Variable}; 9 | use crate::query::Key; 10 | use crate::span::Span; 11 | 12 | use super::{Mode, Registers}; 13 | 14 | type Entry = u64; 15 | type Exit = u64; 16 | 17 | #[derive(Debug)] 18 | pub struct Scene { 19 | pub mode: Mode, 20 | pub primary: Registers, 21 | pub alternate: Registers, 22 | pub reserved: HashSet, 23 | pub variables: HashMap, 24 | pub loops: Vec<(Entry, Exit)>, 25 | pub parent: Option, 26 | next_offset: isize, 27 | next_label: u64, 28 | } 29 | 30 | impl Scene { 31 | pub fn parameters_offset(&self) -> usize { 32 | self.mode.size().bytes() * 2 33 | } 34 | 35 | pub fn mode_primary(&self) -> iced_x86::Register { 36 | self.primary[self.mode.size()] 37 | } 38 | 39 | pub fn variable(&mut self, variable: Variable, size: usize) -> isize { 40 | let next_offset = self.reserve(size); 41 | self.variables.insert(variable, next_offset).unwrap_none(); 42 | next_offset 43 | } 44 | 45 | pub fn reserve(&mut self, size: usize) -> isize { 46 | self.next_offset -= size as isize; 47 | self.next_offset 48 | } 49 | 50 | pub fn label(&mut self) -> u64 { 51 | self.next_label += 1; 52 | self.next_label 53 | } 54 | } 55 | 56 | #[derive(Debug, Default)] 57 | pub struct Translation { 58 | pub pending_label: Option, 59 | pub instructions: Vec, 60 | pub calls: Vec<(usize, FunctionPath)>, 61 | pub spans: Vec, 62 | } 63 | 64 | impl Translation { 65 | pub fn set_pending_label(&mut self, label: u64, span: &Span) { 66 | if self.pending_label.is_some() { 67 | let code = iced_x86::Code::Nopw; 68 | self.push(Instruction::with(code), span); 69 | } 70 | 71 | assert!(self.pending_label.is_none()); 72 | self.pending_label = Some(label); 73 | } 74 | 75 | pub fn push(&mut self, mut instruction: Instruction, span: &Span) { 76 | self.pending_label.take().into_iter() 77 | .for_each(|label| instruction.set_ip(label)); 78 | self.instructions.push(instruction); 79 | self.spans.push(span.clone()); 80 | } 81 | } 82 | 83 | pub fn lower(context: &Context, parent: Option, path: &FunctionPath, 84 | span: Option) -> crate::Result> { 85 | let key = Key::Generate(path.clone()); 86 | context.sections.scope(parent, key.clone(), span.clone(), || { 87 | let parent = Some(key.clone()); 88 | let translation = translate(context, parent, path, Mode::Long, span)?; 89 | let block = InstructionBlock::new(&translation.instructions, 0); 90 | 91 | // TODO: remove display code 92 | use iced_x86::Formatter; 93 | let buffer = &mut String::new(); 94 | let mut formatter = iced_x86::NasmFormatter::new(); 95 | for instruction in &translation.instructions { 96 | formatter.format(instruction, buffer); 97 | println!("{}", buffer); 98 | buffer.clear(); 99 | } 100 | println!(); 101 | 102 | let mut encoder = BlockEncoderOptions::RETURN_CONSTANT_OFFSETS; 103 | encoder |= BlockEncoderOptions::RETURN_NEW_INSTRUCTION_OFFSETS; 104 | let block = BlockEncoder::encode(64, block, encoder).unwrap_or_else(|error| 105 | panic!("encoding failure in: {:?}, where: {}", path, error)); 106 | 107 | let mut section = Section::default(); 108 | for (index, path) in translation.calls { 109 | let offset = block.new_instruction_offsets[index] as usize; 110 | let offset = offset + block.constant_offsets[index].immediate_offset(); 111 | let target = block.new_instruction_offsets.get(index + 1).cloned() 112 | .unwrap_or(block.code_buffer.len() as u32) as usize; 113 | 114 | let size = Size::Double; 115 | let relative = Relative { size, offset, path, target }; 116 | section.relative.push(relative); 117 | } 118 | 119 | section.bytes = block.code_buffer; 120 | Ok(section) 121 | }) 122 | } 123 | 124 | pub fn translate(context: &Context, parent: Option, path: &FunctionPath, 125 | mode: Mode, span: Option) -> crate::Result { 126 | let function = &crate::node::function(context, parent.clone(), path, span.clone())?; 127 | let types = crate::inference::type_function(context, parent.clone(), path, span)?; 128 | let reserved = super::reserved(context, function, mode)?; 129 | let (primary, alternate) = super::registers(context, 130 | &reserved, mode, &function.identifier.span)?; 131 | 132 | let (next_offset, next_label) = (0, 0); 133 | let (variables, loops) = (HashMap::new(), Vec::new()); 134 | let scene = &mut Scene { 135 | mode, 136 | primary, 137 | alternate, 138 | reserved, 139 | variables, 140 | loops, 141 | parent, 142 | next_offset, 143 | next_label, 144 | }; 145 | 146 | let mut translation = Translation::default(); 147 | super::entry(scene, &mut translation, &function.identifier.span); 148 | super::parameters(context, function, scene)?; 149 | 150 | // TODO: remove special main 151 | if function.identifier.node == crate::node::Identifier("main".to_string()) { 152 | super::value(context, scene, &mut translation, 153 | &types, &function.value, &function.value.root)?; 154 | define_note!(note, translation, &function.identifier.span); 155 | note(Instruction::with_reg_reg(iced_x86::Code::Mov_r64_rm64, 156 | iced_x86::Register::RDI, iced_x86::Register::RAX)); 157 | note(Instruction::with_reg_i64(iced_x86::Code::Mov_r64_imm64, 158 | iced_x86::Register::RAX, (2 << 24) | (!(0xff << 24) & 1))); 159 | note(Instruction::with(iced_x86::Code::Syscall)); 160 | let frame_size = -scene.next_offset as i32; 161 | translation.instructions[2].set_immediate_i32(1, frame_size); 162 | return Ok(translation); 163 | } 164 | 165 | let root = function.value.root; 166 | super::render(context, scene, &mut translation, &types, 167 | &function.value, Some(root), &function.value[root].span)?; 168 | 169 | let frame_size = -scene.next_offset as i32; 170 | if frame_size != 0 { 171 | translation.instructions[2].set_immediate_i32(1, frame_size); 172 | } else { 173 | translation.instructions.remove(2); 174 | translation.calls.iter_mut().for_each(|(index, _)| *index -= 1); 175 | } 176 | 177 | Ok(translation) 178 | } 179 | -------------------------------------------------------------------------------- /src/generate/x86/mod.rs: -------------------------------------------------------------------------------- 1 | pub use binary::*; 2 | pub use call::*; 3 | pub use cast::*; 4 | pub use function::*; 5 | pub use lower::*; 6 | pub use node::*; 7 | pub use register::*; 8 | pub use target::*; 9 | pub use value::*; 10 | 11 | #[macro_use] 12 | mod node; 13 | mod lower; 14 | mod value; 15 | mod binary; 16 | mod target; 17 | mod register; 18 | mod function; 19 | mod call; 20 | mod cast; 21 | -------------------------------------------------------------------------------- /src/generate/x86/node.rs: -------------------------------------------------------------------------------- 1 | use iced_x86::{Code, Register}; 2 | use iced_x86::Instruction as I; 3 | 4 | use crate::context::Context; 5 | use crate::error::Diagnostic; 6 | use crate::node::{Size, Type}; 7 | use crate::span::Span; 8 | 9 | use super::{Scene, Translation}; 10 | 11 | macro_rules! define_note { 12 | ($note:ident, $prime:expr, $span:expr) => { 13 | let $note = &mut |instruction| $prime.push(instruction, $span); 14 | }; 15 | } 16 | 17 | macro_rules! register { 18 | ($size:expr, $index:ident) => {{ 19 | use iced_x86::Register::*; 20 | match $size { 21 | Size::Byte => concat_idents!($index, L), 22 | Size::Word => concat_idents!($index, X), 23 | Size::Double => concat_idents!(E, $index, X), 24 | Size::Quad => concat_idents!(R, $index, X), 25 | } 26 | }}; 27 | } 28 | 29 | macro_rules! relative { 30 | ($mode:expr, $prefix:ident) => {{ 31 | use iced_x86::Code::*; 32 | use super::Mode; 33 | match $mode { 34 | Mode::Protected => concat_idents!($prefix, _rel32_64), 35 | Mode::Long => concat_idents!($prefix, _rel32_64), 36 | Mode::Real => concat_idents!($prefix, _rel32_32), 37 | } 38 | }}; 39 | } 40 | 41 | macro_rules! code_m { 42 | ($size:expr, $identifier:ident $(,$other:ident)*) => {{ 43 | use iced_x86::Code::*; 44 | match $size { 45 | Size::Byte => concat_idents!($identifier, m8, $($other,)*), 46 | Size::Word => concat_idents!($identifier, m16, $($other,)*), 47 | Size::Double => concat_idents!($identifier, m32, $($other,)*), 48 | Size::Quad => concat_idents!($identifier, m64, $($other,)*), 49 | } 50 | }}; 51 | } 52 | 53 | macro_rules! code_rm { 54 | ($size:expr, $left:ident, $right:ident) => {{ 55 | use iced_x86::Code::*; 56 | match $size { 57 | Size::Byte => concat_idents!($left, r8, $right, m8), 58 | Size::Word => concat_idents!($left, r16, $right, m16), 59 | Size::Double => concat_idents!($left, r32, $right, m32), 60 | Size::Quad => concat_idents!($left, r64, $right, m64), 61 | } 62 | }}; 63 | } 64 | 65 | pub fn code_push(size: Size) -> Code { 66 | match size { 67 | Size::Byte => Code::Push_r16, 68 | Size::Word => Code::Push_r16, 69 | Size::Double => Code::Push_r32, 70 | Size::Quad => Code::Push_r64, 71 | } 72 | } 73 | 74 | pub fn code_pop(size: Size) -> Code { 75 | match size { 76 | Size::Byte => Code::Pop_r16, 77 | Size::Word => Code::Pop_r16, 78 | Size::Double => Code::Pop_r32, 79 | Size::Quad => Code::Pop_r64, 80 | } 81 | } 82 | 83 | pub fn code_sign_extend(size: Size) -> Code { 84 | match size { 85 | Size::Byte => Code::Cbw, 86 | Size::Word => Code::Cwd, 87 | Size::Double => Code::Cdq, 88 | Size::Quad => Code::Cqo, 89 | } 90 | } 91 | 92 | /// Moves a value between two registers if they are different. 93 | pub fn transfer(prime: &mut Translation, register: Register, 94 | target: Register, size: Size, span: &Span) { 95 | if register != target { 96 | define_note!(note, prime, span); 97 | let code = code_rm!(size, Mov_, _r); 98 | note(I::with_reg_reg(code, target, register)); 99 | } 100 | } 101 | 102 | /// Reserves a register for use. If the register is already 103 | /// reserved then it is saved and restored off the stack. 104 | /// Temporarily marks the register as reserved. 105 | pub fn reserve(scene: &mut Scene, prime: &mut Translation, 106 | target: Register, function: F, size: Size, span: &Span) 107 | where F: FnOnce(&mut Scene, &mut Translation) { 108 | let registers = super::register_set(target); 109 | let free = !scene.reserved.contains(®isters); 110 | 111 | define_note!(note, prime, span); 112 | if !free { note(I::with_reg(code_push(size), target)); } 113 | if free { scene.reserved.insert(registers.clone()); } 114 | function(scene, prime); 115 | 116 | define_note!(note, prime, span); 117 | if free { scene.reserved.remove(®isters); } 118 | if !free { note(I::with_reg(code_pop(size), target)); } 119 | } 120 | 121 | /// Tries to use a register if it is not reserved. If it is, the register 122 | /// is reserved and saved and the existing value is transferred to the default 123 | /// register. The register used is provided to the closure. 124 | pub fn convey(scene: &mut Scene, prime: &mut Translation, register: Register, 125 | default: Register, function: F, size: Size, span: &Span) 126 | where F: FnOnce(&Scene, &mut Translation, Register) { 127 | let registers = super::register_set(register); 128 | match scene.reserved.contains(®isters) { 129 | false => function(scene, prime, register), 130 | true => reserve(scene, prime, default, |scene, prime| { 131 | transfer(prime, register, default, size, span); 132 | function(scene, prime, default) 133 | }, size, span), 134 | } 135 | } 136 | 137 | /// Returns the size of the machine code representation for a type. 138 | /// Composite types take the same size as a pointer. 139 | pub fn size(context: &Context, scene: &Scene, path: &Type, 140 | span: &Span) -> crate::Result { 141 | let size = match path { 142 | Type::Truth => Size::Byte, 143 | Type::Rune => Size::Double, 144 | Type::Signed(size) | Type::Unsigned(size) => *size, 145 | Type::Void | Type::Never => return context.pass(Diagnostic::error() 146 | .message(format!("cannot lower values of type: {}", path)) 147 | .label(span.label())), 148 | Type::Structure(_) | Type::Array(_, _) | Type::Slice(_) 149 | | Type::Pointer(_) => scene.mode.size(), 150 | }; 151 | 152 | let mode = scene.mode as u8; 153 | match size as u8 > mode { 154 | true => context.pass(Diagnostic::error() 155 | .label(span.label().with_message(path.to_string())) 156 | .message(format!("unsupported type for architecture: x{}", mode))), 157 | false => Ok(size), 158 | } 159 | } 160 | 161 | /// Promotes byte sizes to words. Bytes cannot be 162 | /// directly used in stack instructions. 163 | pub fn stack(size: Size) -> Size { 164 | match size { 165 | Size::Byte => Size::Word, 166 | other => other, 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/generate/x86/register.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashSet; 2 | use std::ops::Index; 3 | 4 | use iced_x86::Register::{self, *}; 5 | 6 | use crate::context::Context; 7 | use crate::error::Diagnostic; 8 | use crate::node::{Function, Identifier, Parameter, Size, ValueNode}; 9 | use crate::span::Span; 10 | 11 | #[derive(Debug, Copy, Clone)] 12 | pub enum Mode { 13 | Protected = 32, 14 | Long = 64, 15 | Real = 16, 16 | } 17 | 18 | impl Mode { 19 | pub fn size(&self) -> Size { 20 | match self { 21 | Mode::Protected => Size::Double, 22 | Mode::Long => Size::Quad, 23 | Mode::Real => Size::Word, 24 | } 25 | } 26 | 27 | pub fn base(&self) -> Register { 28 | match self { 29 | Mode::Protected => Register::EBP, 30 | Mode::Long => Register::RBP, 31 | Mode::Real => Register::BP, 32 | } 33 | } 34 | 35 | pub fn stack(&self) -> Register { 36 | match self { 37 | Mode::Protected => Register::ESP, 38 | Mode::Long => Register::RSP, 39 | Mode::Real => Register::SP, 40 | } 41 | } 42 | 43 | pub fn destination(&self) -> Register { 44 | match self { 45 | Mode::Protected => Register::EDI, 46 | Mode::Long => Register::RDI, 47 | Mode::Real => Register::DI, 48 | } 49 | } 50 | } 51 | 52 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 53 | pub struct Registers([Register; 4]); 54 | 55 | impl Index for Registers { 56 | type Output = Register; 57 | 58 | fn index(&self, index: Size) -> &Self::Output { 59 | let Registers(registers) = self; 60 | match index { 61 | Size::Byte => ®isters[0], 62 | Size::Word => ®isters[1], 63 | Size::Double => ®isters[2], 64 | Size::Quad => ®isters[3], 65 | } 66 | } 67 | } 68 | 69 | macro_rules! define_registers { 70 | ($set:ident, $string:ident, $table:ident, 71 | [$(($($variant:ident: $identifier:expr),* 72 | $(; $other:ident: $extra:expr)?),)*]) => { 73 | const $set: &'static [Registers] = 74 | &[$(Registers([$($variant,)*]),)*]; 75 | 76 | fn $string(string: &str) -> Option { 77 | Some(match string { 78 | $($($identifier => $variant,)* $($extra => $other,)?)* 79 | _ => return std::option::Option::None, 80 | }) 81 | } 82 | 83 | #[allow(unreachable_patterns)] 84 | fn $table(register: Register) -> Option { 85 | Some(match register { 86 | $($($variant |)* $($other |)? 87 | None => Registers([$($variant,)*]),)* 88 | _ => return std::option::Option::None, 89 | }) 90 | } 91 | }; 92 | } 93 | 94 | define_registers!(SET, string, table, [ 95 | (AL: "al", AX: "ax", EAX: "eax", RAX: "rax"; AH: "ah"), 96 | (BL: "bl", BX: "bx", EBX: "ebx", RBX: "rbx"; BH: "bh"), 97 | (CL: "cl", CX: "cx", ECX: "ecx", RCX: "rcx"; CH: "ch"), 98 | (DL: "dl", DX: "dx", EDX: "edx", RDX: "rdx"; DH: "dh"), 99 | (SIL: "sil", SI: "si", ESI: "esi", RSI: "rsi"), 100 | (DIL: "dil", DI: "di", EDI: "edi", RDI: "rdi"), 101 | ]); 102 | 103 | define_registers!(_STACK_SET, stack_string, stack_table, [ 104 | (BPL: "bpl", BP: "bp", EBP: "ebp", RBP: "rbp"), 105 | (SPL: "spl", SP: "sp", ESP: "esp", RSP: "rsp"), 106 | ]); 107 | 108 | define_registers!(LONG_SET, long_string, long_table, [ 109 | (R8L: "r8l", R8W: "r8w", R8D: "r8d", R8: "r8"), 110 | (R9L: "r9l", R9W: "r9w", R9D: "r9d", R9: "r9"), 111 | (R10L: "r10l", R10W: "r10w", R10D: "r10d", R10: "r10"), 112 | (R11L: "r11l", R11W: "r11w", R11D: "r11d", R11: "r11"), 113 | (R12L: "r12l", R12W: "r12w", R12D: "r12d", R12: "r12"), 114 | (R13L: "r13l", R13W: "r13w", R13D: "r13d", R13: "r13"), 115 | (R14L: "r14l", R14W: "r14w", R14D: "r14d", R14: "r14"), 116 | (R15L: "r15l", R15W: "r15w", R15D: "r15d", R15: "r15"), 117 | ]); 118 | 119 | pub fn register_set(register: Register) -> Registers { 120 | table(register).or(stack_table(register)).or(long_table(register)) 121 | .unwrap_or_else(|| panic!("invalid register: {:?}", register)) 122 | } 123 | 124 | pub fn register(context: &Context, mode: Mode, register: &Identifier, 125 | span: &Span) -> crate::Result { 126 | let Identifier(register) = register; 127 | let long = matches!(mode, Mode::Long) 128 | .then_some(long_string(register)).flatten(); 129 | string(register).or(stack_string(register)).or(long) 130 | .ok_or_else(|| context.error(Diagnostic::error() 131 | .message("invalid register").label(span.label()))) 132 | } 133 | 134 | pub fn reserved(context: &Context, function: &Function, 135 | mode: Mode) -> crate::Result> { 136 | let mut reserved = HashSet::new(); 137 | function.parameters.iter().try_for_each(|parameter| 138 | Ok(if let Parameter::Register(register) = ¶meter.node { 139 | self::register(context, mode, ®ister.node, ®ister.span) 140 | .map(|register| reserved.insert(register_set(register)))?; 141 | }))?; 142 | function.value.values.iter().try_for_each(|value| 143 | Ok(if let ValueNode::Register(register) = &value.node { 144 | self::register(context, mode, register, &value.span) 145 | .map(|register| reserved.insert(register_set(register)))?; 146 | }))?; 147 | Ok(reserved) 148 | } 149 | 150 | pub fn registers(context: &Context, reserved: &HashSet, mode: Mode, 151 | span: &Span) -> crate::Result<(Registers, Registers)> { 152 | let long = matches!(mode, Mode::Long).then_some(LONG_SET.iter()); 153 | let mut iterator = Iterator::chain(SET.iter(), long.into_iter().flatten()) 154 | .filter(|registers| !reserved.contains(registers)).cloned(); 155 | let (primary, alternate) = (iterator.next(), iterator.next()); 156 | Iterator::zip(primary.into_iter(), alternate.into_iter()) 157 | .next().ok_or_else(|| context.error(Diagnostic::error() 158 | .message("unable to allocate registers for function") 159 | .note("two free registers required") 160 | .label(span.label()))) 161 | } 162 | -------------------------------------------------------------------------------- /src/generate/x86/target.rs: -------------------------------------------------------------------------------- 1 | use iced_x86::Code; 2 | use iced_x86::Instruction as I; 3 | use iced_x86::MemoryOperand as M; 4 | 5 | use crate::context::Context; 6 | use crate::error::Diagnostic; 7 | use crate::inference::Types; 8 | use crate::node::{Dual, Size, Type, Unary, Value, ValueIndex, ValueNode}; 9 | use crate::span::Span; 10 | 11 | use super::{Mode, Scene, Translation}; 12 | 13 | pub fn target(context: &Context, scene: &mut Scene, prime: &mut Translation, 14 | types: &Types, value: &Value, index: &ValueIndex) -> crate::Result { 15 | let span = &value[*index].span; 16 | match &value[*index].node { 17 | // TODO: path as start address intrinsic 18 | ValueNode::Path(_) => unimplemented!(), 19 | ValueNode::Variable(variable) => { 20 | let offset = scene.variables[variable] as i32; 21 | Ok(M::with_base_displ(scene.mode.base(), offset)) 22 | } 23 | ValueNode::Field(index, field) => { 24 | let mut target = target(context, scene, prime, types, value, index)?; 25 | let offset = crate::node::offset(context, scene.parent.clone(), 26 | &types[index], &field.node, Some(span.clone()))?; 27 | target.displacement += offset as i32; 28 | assert_eq!(target.displ_size, 1); 29 | Ok(target) 30 | } 31 | ValueNode::Index(target, index) => match &types[target] { 32 | Type::Array(path, _) => { 33 | let scale = crate::node::size(context, scene 34 | .parent.clone(), &path.node, Some(span.clone()))?; 35 | let target = self::target(context, scene, prime, types, value, target)?; 36 | 37 | define_note!(note, prime, span); 38 | note(I::with_reg_mem(load(scene.mode), scene.mode_primary(), target)); 39 | note(I::with_reg(super::code_push(scene.mode.size()), scene.mode_primary())); 40 | swap_restore(context, scene, prime, types, value, index, span)?; 41 | scale_index(scene, prime, &types[index], scale, Dual::Add, span)?; 42 | Ok(M::with_base(scene.mode_primary())) 43 | } 44 | Type::Slice(path) => { 45 | let scale = crate::node::size(context, scene 46 | .parent.clone(), &path.node, Some(span.clone()))?; 47 | super::value(context, scene, prime, types, value, target)?; 48 | prime.push(I::with_mem(super::code_push(scene.mode.size()), 49 | M::with_base(scene.mode_primary())), span); 50 | 51 | swap_restore(context, scene, prime, types, value, index, span)?; 52 | scale_index(scene, prime, &types[index], scale, Dual::Add, span)?; 53 | Ok(M::with_base(scene.mode_primary())) 54 | } 55 | other => panic!("cannot index into type: {}", other) 56 | } 57 | ValueNode::Unary(Unary::Dereference, index) => { 58 | super::value(context, scene, prime, types, value, index)?; 59 | Ok(M::with_base(scene.mode_primary())) 60 | } 61 | _ => context.pass(Diagnostic::error() 62 | .message("value is not addressable") 63 | .label(span.label())), 64 | } 65 | } 66 | 67 | pub fn scale_index(scene: &mut Scene, prime: &mut Translation, index: &Type, 68 | scale: usize, dual: Dual, span: &Span) -> crate::Result<()> { 69 | define_note!(note, prime, span); 70 | let target = scene.mode.size(); 71 | match index { 72 | Type::Signed(size) => super::sign_extend(scene, *size, target) 73 | .into_iter().for_each(|instruction| note(instruction)), 74 | Type::Unsigned(size) => super::zero_extend(scene, *size, target) 75 | .into_iter().for_each(|instruction| note(instruction)), 76 | other => panic!("invalid arithmetic type: {}", other), 77 | } 78 | 79 | let alternate = scene.alternate[target]; 80 | note(I::with_reg_reg_i32(match scene.mode { 81 | Mode::Protected => Code::Imul_r32_rm32_imm32, 82 | Mode::Long => Code::Imul_r64_rm64_imm32, 83 | Mode::Real => Code::Imul_r16_rm16_imm16, 84 | }, alternate, alternate, scale as i32)); 85 | Ok(note(I::with_reg_reg(match dual { 86 | Dual::Add => code_rm!(target, Add_, _r), 87 | Dual::Minus => code_rm!(target, Sub_, _r), 88 | other => panic!("invalid scale dual: {:?}", other), 89 | }, scene.primary[target], alternate))) 90 | } 91 | 92 | pub fn load(mode: Mode) -> Code { 93 | match mode { 94 | Mode::Protected => Code::Lea_r32_m, 95 | Mode::Long => Code::Lea_r64_m, 96 | Mode::Real => Code::Lea_r16_m, 97 | } 98 | } 99 | 100 | fn swap_restore(context: &Context, scene: &mut Scene, prime: &mut Translation, 101 | types: &Types, value: &Value, index: &ValueIndex, 102 | span: &Span) -> crate::Result<()> { 103 | std::mem::swap(&mut scene.primary, &mut scene.alternate); 104 | super::value(context, scene, prime, types, value, index)?; 105 | std::mem::swap(&mut scene.primary, &mut scene.alternate); 106 | Ok(prime.push(I::with_reg(super::code_pop(scene.mode 107 | .size()), scene.mode_primary()), span)) 108 | } 109 | -------------------------------------------------------------------------------- /src/generate/x86/value.rs: -------------------------------------------------------------------------------- 1 | use iced_x86::Code; 2 | use iced_x86::Instruction as I; 3 | use iced_x86::MemoryOperand as M; 4 | 5 | use crate::context::Context; 6 | use crate::error::Diagnostic; 7 | use crate::inference::Types; 8 | use crate::node::*; 9 | use crate::query::QueryError; 10 | 11 | use super::{Mode, Scene, Translation}; 12 | 13 | pub fn value(context: &Context, scene: &mut Scene, prime: &mut Translation, 14 | types: &Types, value: &Value, index: &ValueIndex) -> crate::Result<()> { 15 | let span = &value[*index].span; 16 | define_note!(note, prime, span); 17 | Ok(match &value[*index].node { 18 | ValueNode::Block(block) => block.iter().try_for_each(|index| 19 | self::value(context, scene, prime, types, value, index))?, 20 | ValueNode::Let(variable, _, index) => { 21 | let size = crate::node::size(context, scene.parent.clone(), 22 | &types.variables[&variable.node], Some(span.clone()))?; 23 | let offset = scene.variable(variable.node.clone(), size); 24 | 25 | if let Some(index) = index { 26 | self::value(context, scene, prime, types, value, index)?; 27 | let memory = M::with_base_displ(scene.mode.base(), offset as i32); 28 | let register = super::size(context, scene, &types[index], span)?; 29 | super::set(scene, prime, &types[index], size, 30 | memory, scene.primary[register], span); 31 | } else { 32 | super::zero(scene, prime, offset, size, span); 33 | } 34 | } 35 | ValueNode::Set(target, index) => { 36 | self::value(context, scene, prime, types, value, index)?; 37 | let size = super::size(context, scene, &types[index], span)?; 38 | let stack = super::stack(size); 39 | 40 | define_note!(note, prime, span); 41 | note(I::with_reg(super::code_push(stack), scene.primary[stack])); 42 | let target = super::target(context, scene, prime, types, value, target)?; 43 | 44 | define_note!(note, prime, span); 45 | let node_size = crate::node::size(context, scene 46 | .parent.clone(), &types[index], Some(span.clone()))?; 47 | note(I::with_reg(super::code_pop(stack), scene.alternate[stack])); 48 | super::set(scene, prime, &types[index], node_size, 49 | target, scene.alternate[size], span); 50 | } 51 | ValueNode::While(condition, index) => { 52 | let entry = *prime.pending_label.get_or_insert_with(|| scene.label()); 53 | self::value(context, scene, prime, types, value, condition)?; 54 | 55 | let exit = scene.label(); 56 | scene.loops.push((entry, exit)); 57 | define_note!(note, prime, span); 58 | let register = scene.primary[Size::Byte]; 59 | note(I::with_reg_reg(Code::Test_rm8_r8, register, register)); 60 | note(I::with_branch(relative!(scene.mode, Je), exit)); 61 | self::value(context, scene, prime, types, value, index)?; 62 | 63 | scene.loops.pop(); 64 | define_note!(note, prime, span); 65 | note(I::with_branch(relative!(scene.mode, Jmp), entry)); 66 | prime.set_pending_label(exit, span); 67 | } 68 | ValueNode::When(branches) => { 69 | let mut complete = false; 70 | let labels: Result, _> = branches.iter().map(|(condition, _)| { 71 | self::value(context, scene, prime, types, value, condition)?; 72 | complete |= matches!(value[*condition].node, ValueNode::Truth(true)); 73 | 74 | let label = scene.label(); 75 | define_note!(note, prime, span); 76 | let register = scene.primary[Size::Byte]; 77 | note(I::with_reg_reg(Code::Test_rm8_r8, register, register)); 78 | note(I::with_branch(relative!(scene.mode, Jne), label)); 79 | Ok(label) 80 | }).collect(); 81 | 82 | let exit = scene.label(); 83 | define_note!(note, prime, span); 84 | if !complete { note(I::with_branch(relative!(scene.mode, Jmp), exit)); } 85 | let iterator = Iterator::zip(labels?.into_iter(), branches.iter()); 86 | for (index, (label, (_, branch))) in iterator.enumerate() { 87 | prime.set_pending_label(label, span); 88 | self::value(context, scene, prime, types, value, branch)?; 89 | 90 | if index + 1 != branches.len() { 91 | define_note!(note, prime, span); 92 | note(I::with_branch(relative!(scene.mode, Jmp), exit)); 93 | } 94 | } 95 | 96 | prime.set_pending_label(exit, span); 97 | } 98 | ValueNode::Cast(index, target) => super::cast(context, 99 | scene, prime, types, value, index, target, span)?, 100 | ValueNode::Return(index) => super::render(context, 101 | scene, prime, types, value, *index, span)?, 102 | ValueNode::Compile(_) => unimplemented!(), 103 | ValueNode::Inline(_) => unimplemented!(), 104 | ValueNode::Call(path, arguments) => super::call(context, scene, 105 | prime, types, value, index, path, &arguments, span)?, 106 | ValueNode::Field(node, field) => { 107 | self::value(context, scene, prime, types, value, node)?; 108 | let offset = crate::node::offset(context, scene.parent.clone(), 109 | &types[node], &field.node, Some(span.clone()))? as i32; 110 | 111 | define_note!(note, prime, span); 112 | if types[index].composite() { 113 | note(I::with_reg_i32(match scene.mode { 114 | Mode::Protected => Code::Add_rm32_imm32, 115 | Mode::Long => Code::Add_rm64_imm32, 116 | Mode::Real => Code::Add_rm16_imm16, 117 | }, scene.mode_primary(), offset)); 118 | } else { 119 | let size = super::size(context, scene, &types[index], span)?; 120 | let memory = M::with_base_displ(scene.mode_primary(), offset); 121 | note(I::with_reg_mem(code_rm!(size, Mov_, _r), 122 | scene.primary[size], memory)); 123 | } 124 | } 125 | ValueNode::Create(path, fields) => { 126 | let offsets = crate::node::offsets(context, scene 127 | .parent.clone(), &path.node, Some(span.clone()))?; 128 | let structure = context.structures.get(&path.node) 129 | .ok_or(QueryError::Failure)?; 130 | let base = scene.reserve(offsets.size); 131 | 132 | for (identifier, offset) in &offsets.fields { 133 | let path = &structure.fields[identifier].node; 134 | let node_size = crate::node::size(context, 135 | scene.parent.clone(), &path, Some(span.clone()))?; 136 | let offset = base + *offset as isize; 137 | 138 | if let Some((index, _)) = fields.get(identifier) { 139 | let size = super::size(context, scene, path, span)?; 140 | self::value(context, scene, prime, types, value, index)?; 141 | let memory = M::with_base_displ(scene.mode.base(), offset as i32); 142 | super::set(scene, prime, path, node_size, memory, 143 | scene.primary[size], span); 144 | } else { 145 | super::zero(scene, prime, offset, node_size, span); 146 | } 147 | } 148 | 149 | let memory = M::with_base_displ(scene.mode.base(), base as i32); 150 | prime.push(I::with_reg_mem(super::load(scene.mode), 151 | scene.mode_primary(), memory), span); 152 | } 153 | ValueNode::Slice(_, _, _) => unimplemented!(), 154 | ValueNode::Index(_, _) => unimplemented!(), 155 | ValueNode::Compound(dual, target, index) => { 156 | super::binary(context, scene, prime, types, 157 | value, &Binary::Dual(*dual), target, index, span)?; 158 | let size = super::size(context, scene, &types[index], span)?; 159 | let stack = super::stack(size); 160 | 161 | define_note!(note, prime, span); 162 | note(I::with_reg(super::code_push(stack), scene.primary[stack])); 163 | let target = super::target(context, scene, prime, types, value, target)?; 164 | 165 | define_note!(note, prime, span); 166 | let node_size = crate::node::size(context, scene 167 | .parent.clone(), &types[index], Some(span.clone()))?; 168 | note(I::with_reg(super::code_pop(stack), scene.alternate[stack])); 169 | super::set(scene, prime, &types[index], node_size, 170 | target, scene.alternate[size], span); 171 | } 172 | ValueNode::Binary(binary, left, right) => super::binary(context, 173 | scene, prime, types, value, binary, left, right, span)?, 174 | ValueNode::Unary(unary, index) => { 175 | if let Unary::Reference = unary { 176 | let instruction = I::with_reg_mem(super::load(scene.mode), 177 | scene.mode_primary(), super::target(context, 178 | scene, prime, types, value, index)?); 179 | return Ok(prime.push(instruction, span)); 180 | } 181 | 182 | let size = super::size(context, scene, &types[index], span)?; 183 | self::value(context, scene, prime, types, value, index)?; 184 | let primary = scene.primary[size]; 185 | define_note!(note, prime, span); 186 | match unary { 187 | Unary::Reference => unreachable!(), 188 | Unary::Not => note(match types[index] { 189 | Type::Truth => I::with_reg_i32(Code::Xor_rm8_imm8, 190 | scene.primary[Size::Byte], 1), 191 | _ => I::with_reg(code_m!(size, Not_r), primary), 192 | }), 193 | Unary::Negate => note(I::with_reg(code_m!(size, Neg_r), primary)), 194 | Unary::Dereference => if types[index].composite() { 195 | let node_size = crate::node::size(context, scene 196 | .parent.clone(), &types[index], Some(span.clone()))?; 197 | let offset = scene.reserve(node_size) as i32; 198 | let memory = M::with_base_displ(scene.mode.base(), offset); 199 | super::set(scene, prime, &types[index], 200 | node_size, memory, primary, span); 201 | prime.push(I::with_reg_mem(super::load(scene.mode), 202 | scene.primary[size], memory), span); 203 | }, 204 | } 205 | } 206 | ValueNode::Variable(variable) => { 207 | let offset = scene.variables[variable] as i32; 208 | let memory = M::with_base_displ(scene.mode.base(), offset); 209 | let path = &types.variables[variable]; 210 | 211 | let size = super::size(context, scene, path, span)?; 212 | note(I::with_reg_mem(match path.composite() { 213 | false => code_rm!(size, Mov_, _r), 214 | true => super::load(scene.mode), 215 | }, scene.primary[size], memory)); 216 | } 217 | ValueNode::Path(_) => unimplemented!(), 218 | ValueNode::String(_) => unimplemented!(), 219 | ValueNode::Register(_) => unimplemented!(), 220 | ValueNode::Array(_) => unimplemented!(), 221 | ValueNode::Integral(integral) => match types[index] { 222 | Type::Signed(size) | Type::Unsigned(size) => { 223 | let integral = *integral as i64; 224 | let register = scene.primary[size]; 225 | let code = code_rm!(size, Mov_, _im); 226 | note(I::with_reg_i64(code, register, integral)); 227 | } 228 | _ => panic!("type is not integral"), 229 | }, 230 | ValueNode::Truth(truth) => 231 | note(I::with_reg_u32(Code::Mov_r8_imm8, 232 | scene.primary[Size::Byte], *truth as u32)), 233 | ValueNode::Rune(rune) => match scene.mode { 234 | Mode::Real => return context.pass(Diagnostic::error() 235 | .message("rune type unsupported for architecture x16") 236 | .label(span.label()).note("use byte literals")), 237 | _ => note(I::with_reg_u32(Code::Mov_r32_imm32, 238 | scene.primary[Size::Double], *rune as u32)), 239 | } 240 | ValueNode::Break => note(I::with_branch(relative!(scene.mode, Jmp), 241 | scene.loops.last().map(|(_, label)| *label).unwrap())), 242 | ValueNode::Continue => note(I::with_branch(relative!(scene.mode, Jmp), 243 | scene.loops.last().map(|(label, _)| *label).unwrap())), 244 | }) 245 | } 246 | -------------------------------------------------------------------------------- /src/inference/context.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::ops::Index; 3 | use std::sync::Arc; 4 | 5 | use crate::context::Context; 6 | use crate::error::Diagnostic; 7 | use crate::node::*; 8 | use crate::query::{Key, QueryError}; 9 | use crate::span::{S, Span}; 10 | 11 | use super::{Scene, Terminal}; 12 | 13 | #[derive(Debug, Default)] 14 | pub struct Types { 15 | pub types: HashMap, 16 | pub variables: HashMap, 17 | pub functions: HashMap, 18 | } 19 | 20 | impl Index<&ValueIndex> for Types { 21 | type Output = Type; 22 | 23 | fn index(&self, index: &ValueIndex) -> &Self::Output { 24 | self.types.get(index).unwrap_or_else(|| 25 | panic!("type for index: {}, is absent", index)) 26 | } 27 | } 28 | 29 | pub fn type_function(context: &Context, parent: Option, path: &FunctionPath, 30 | span: Option) -> crate::Result> { 31 | let key = Key::TypeFunction(path.clone()); 32 | context.type_contexts.scope(parent, key.clone(), span.clone(), || { 33 | let function = &crate::node::function(context, 34 | Some(key.clone()), path, span.clone())?; 35 | let mut scene = Scene::default(); 36 | scene.parent = Some(key); 37 | 38 | for parameter in &function.parameters { 39 | if let Parameter::Variable(variable, node) = parameter.node.clone() { 40 | let type_variable = scene.next(); 41 | scene.variables.insert(variable.node, (type_variable, variable.span)); 42 | let terminal = Terminal::Type(S::new(node.node, node.span)); 43 | scene.terminals.insert(type_variable, terminal); 44 | } 45 | } 46 | 47 | let place = S::new(scene.next(), function.return_type.span.clone()); 48 | if let ReturnType::Type(node) = function.return_type.node.clone() { 49 | let terminal = S::new(node.node, node.span.clone()); 50 | let variable = scene.next_with(Terminal::Type(terminal)); 51 | scene.unify(context, variable, place.node, &node.span, &place.span); 52 | } 53 | 54 | let root = super::value(context, &mut scene, 55 | Some(&place), &function.value, &function.value.root)?; 56 | match function.return_type.node.clone() { 57 | ReturnType::Type(S { node: Type::Void, .. }) | 58 | ReturnType::Type(S { node: Type::Never, .. }) => (), 59 | ReturnType::Type(node) => { 60 | let terminal = S::new(node.node, node.span.clone()); 61 | let variable = scene.next_with(Terminal::Type(terminal)); 62 | let span = &function.value[function.value.root].span; 63 | scene.unify(context, root, variable, span, &node.span); 64 | } 65 | _ => (), 66 | } 67 | 68 | match scene.failure { 69 | true => Err(QueryError::Failure), 70 | false => types(context, &function.value, scene), 71 | } 72 | }) 73 | } 74 | 75 | pub fn type_variable(context: &Context, parent: Option, path: Path, 76 | span: Option) -> crate::Result> { 77 | let variable = context.statics.get(&path); 78 | let variable = variable.as_ref().ok_or(QueryError::Failure)?; 79 | if let Some(node) = &variable.node_type { return Ok(node.clone()); } 80 | 81 | let key = Key::TypeVariable(path.clone()); 82 | context.type_contexts.scope(parent, key.clone(), span, || { 83 | let mut scene = Scene::default(); 84 | scene.parent = Some(key); 85 | 86 | let value = variable.value.as_ref().unwrap(); 87 | let root = super::value(context, &mut scene, None, value, &value.root)?; 88 | if let Some(node) = &variable.node_type { 89 | let other = scene.next_with(Terminal::Type(node.clone())); 90 | scene.unify(context, root, other, &value[value.root].span, &node.span); 91 | } 92 | 93 | types(context, value, scene) 94 | }).map(|types| { 95 | let node = variable.value.as_ref().unwrap(); 96 | let node = types.types.get(&node.root).unwrap(); 97 | S::new(node.clone(), variable.identifier.span.clone()) 98 | }) 99 | } 100 | 101 | fn types(context: &Context, value: &Value, mut scene: Scene) -> crate::Result { 102 | let mut variables = HashMap::new(); 103 | std::mem::take(&mut scene.variables).into_iter() 104 | .try_for_each(|(variable, (node, span))| match scene.resolve(node) { 105 | Some(node) => Ok(variables.insert(variable, node.node).unwrap_none()), 106 | None => context.pass(Diagnostic::error().label(span.label()) 107 | .message("unresolved type").note("add a type annotation")), 108 | })?; 109 | 110 | let mut types = HashMap::new(); 111 | std::mem::take(&mut scene.values).into_iter() 112 | .try_for_each(|(index, node)| match scene.resolve(node) { 113 | Some(node) => Ok(types.insert(index, node.node).unwrap_none()), 114 | None => context.pass(Diagnostic::error().label(value[index].span.label()) 115 | .message("unresolved type").note("add a type annotation")), 116 | })?; 117 | 118 | let functions = scene.functions; 119 | Ok(Types { types, variables, functions }) 120 | } 121 | -------------------------------------------------------------------------------- /src/inference/mod.rs: -------------------------------------------------------------------------------- 1 | pub use context::*; 2 | pub use path::*; 3 | pub use scene::*; 4 | pub use structure::*; 5 | pub use value::*; 6 | 7 | mod context; 8 | mod structure; 9 | mod path; 10 | mod scene; 11 | mod value; 12 | -------------------------------------------------------------------------------- /src/inference/path.rs: -------------------------------------------------------------------------------- 1 | use crate::context::Context; 2 | use crate::error::Diagnostic; 3 | use crate::node::*; 4 | use crate::span::S; 5 | 6 | use super::{Scene, Terminal, TypeVariable}; 7 | 8 | pub fn path(context: &Context, scene: &mut Scene, value: &Value, 9 | index: &ValueIndex, path: &Path) -> crate::Result { 10 | let span = &value[*index].span; 11 | if context.statics.contains_key(path) { 12 | let node = super::type_variable(context, scene.parent 13 | .clone(), path.clone(), Some(span.clone()))?; 14 | return Ok(scene.ascribe(index, node)); 15 | } 16 | 17 | context.pass(Diagnostic::error() 18 | .message("no symbol value at path") 19 | .label(span.label())) 20 | } 21 | 22 | pub fn function_call(context: &Context, scene: &mut Scene, place: Option<&S>, 23 | value: &Value, index: &ValueIndex, path: &S, arguments: &[ValueIndex]) 24 | -> crate::Result { 25 | let span = value[*index].span.clone(); 26 | if let Some(intrinsic) = intrinsic(context, value, index, path, arguments)? { 27 | return Ok(scene.ascribe(index, S::new(intrinsic, span))); 28 | } 29 | 30 | let span = value[*index].span.clone(); 31 | let arguments: Vec<_> = arguments.iter().map(|index| 32 | super::value(context, scene, place, value, index) 33 | .map(|value| (value, index))).collect::>()?; 34 | let candidates = context.functions.get(&path.node).unwrap(); 35 | let candidates: Vec<_> = candidates.iter().enumerate().filter(|(_, candidate)| 36 | candidate.parameters.len() == arguments.len()).collect(); 37 | 38 | if let [(kind, function)] = candidates.as_slice() { 39 | let iterator = Iterator::zip(arguments.into_iter(), function.parameters.iter()); 40 | for ((argument, index), parameter) in iterator { 41 | if let Parameter::Variable(_, other) = ¶meter.node { 42 | let other = scene.next_with(Terminal::Type(other.clone())); 43 | scene.unify(context, argument, other, &value[*index].span, ¶meter.span); 44 | } 45 | } 46 | 47 | scene.functions.insert(*index, *kind); 48 | return_type(scene, index, &function.return_type) 49 | } else { 50 | let arguments: Vec<_> = arguments.into_iter().map(|(variable, index)| 51 | scene.resolve(variable).ok_or_else(|| context.error(Diagnostic::error() 52 | .label(value[*index].span.label()).message("unresolved type") 53 | .note("add a type annotation")))).collect::>()?; 54 | let mut candidates = candidates.into_iter().filter(|(_, candidate)| 55 | Iterator::zip(arguments.iter(), candidate.parameters.iter()) 56 | .all(|(argument, parameter)| match ¶meter.node { 57 | Parameter::Variable(_, variable) => 58 | Type::equal(context, &argument.node, &variable.node), 59 | Parameter::Register(_) => true, 60 | })); 61 | 62 | let (kind, function) = candidates.next().ok_or_else(|| 63 | context.error(Diagnostic::error().label(span.label()) 64 | .message("no matching function")))?; 65 | 66 | if candidates.next().is_some() { 67 | return context.pass(Diagnostic::error().label(span.label()) 68 | .message("ambiguous function call")); 69 | } 70 | 71 | scene.functions.insert(*index, kind); 72 | return_type(scene, index, &function.return_type) 73 | } 74 | } 75 | 76 | fn intrinsic(context: &Context, value: &Value, index: &ValueIndex, path: &S, 77 | arguments: &[ValueIndex]) -> crate::Result> { 78 | match &path.node { 79 | path if path == &["Intrinsic", "size"][..] => (), 80 | path if path == &["Intrinsic", "start"][..] => (), 81 | path if path == &["Intrinsic", "end"][..] => (), 82 | _ => return Ok(None), 83 | } 84 | 85 | let span = &value[*index].span; 86 | if arguments.len() != 1 { 87 | return context.pass(Diagnostic::error() 88 | .message("expected one argument") 89 | .label(span.label())); 90 | } 91 | 92 | let path = &value[arguments[0]]; 93 | match path.node { 94 | // TODO: use architecture pointer type 95 | ValueNode::Path(_) => Ok(Some(Type::Unsigned(Size::Quad))), 96 | _ => context.pass(Diagnostic::error().message("expected path") 97 | .label(path.span.label())), 98 | } 99 | } 100 | 101 | fn return_type(scene: &mut Scene, index: &ValueIndex, 102 | node: &S) -> crate::Result { 103 | Ok(match &node.node { 104 | ReturnType::Type(node) => scene.ascribe(index, node.clone()), 105 | ReturnType::Register(_) => { 106 | let variable = scene.next(); 107 | *scene.values.entry(*index).insert(variable).get() 108 | } 109 | }) 110 | } 111 | -------------------------------------------------------------------------------- /src/inference/scene.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::fmt; 3 | 4 | use crate::context::Context; 5 | use crate::error::Diagnostic; 6 | use crate::node::{FunctionKind, Size, Type, Value, ValueIndex, ValueNode, Variable}; 7 | use crate::span::{S, Span}; 8 | 9 | pub type TypeVariable = usize; 10 | 11 | #[derive(Debug, Clone)] 12 | pub enum Terminal { 13 | Type(S), 14 | Slice(TypeVariable), 15 | Sequence(TypeVariable), 16 | Array(TypeVariable, usize), 17 | Integral(S), 18 | Pointer(TypeVariable), 19 | } 20 | 21 | impl Terminal { 22 | fn equal(context: &Context, left: &Self, right: &Self) -> bool { 23 | use crate::node::Type as NodeType; 24 | use Terminal::*; 25 | match (left, right) { 26 | (Type(left), Type(right)) => 27 | NodeType::equal(context, &left.node, &right.node), 28 | (Slice(left), Slice(right)) => left == right, 29 | (Sequence(left), Sequence(right)) => left == right, 30 | (Array(left, left_size), Array(right, right_size)) => 31 | left == right && left_size == right_size, 32 | (Integral(left), Integral(right)) => left.node == right.node, 33 | (Pointer(left), Pointer(right)) => left == right, 34 | _ => false, 35 | } 36 | } 37 | } 38 | 39 | impl fmt::Display for Terminal { 40 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 41 | match self { 42 | Terminal::Type(node) => write!(f, "{}", node), 43 | Terminal::Integral(_) => write!(f, "integral"), 44 | Terminal::Sequence(_) => write!(f, "[_; ?]"), 45 | Terminal::Array(_, size) => write!(f, "[_; {}]", size), 46 | Terminal::Slice(_) => write!(f, "[_;]"), 47 | Terminal::Pointer(_) => write!(f, "*type"), 48 | } 49 | } 50 | } 51 | 52 | #[derive(Debug, Default)] 53 | pub struct Scene { 54 | pub parent: Option, 55 | pub terminals: HashMap, 56 | pub parents: HashMap, 57 | pub values: HashMap, 58 | pub variables: HashMap, 59 | pub functions: HashMap, 60 | pub next_type: TypeVariable, 61 | pub failure: bool, 62 | } 63 | 64 | impl Scene { 65 | pub fn next(&mut self) -> TypeVariable { 66 | self.next_type += 1; 67 | self.next_type - 1 68 | } 69 | 70 | pub fn next_with(&mut self, terminal: Terminal) -> TypeVariable { 71 | let variable = self.next(); 72 | self.terminals.insert(variable, terminal); 73 | variable 74 | } 75 | 76 | pub fn unify(&mut self, context: &Context, left: TypeVariable, 77 | right: TypeVariable, left_span: &Span, right_span: &Span) { 78 | use Terminal::{Integral, Array, Slice, Sequence, Pointer}; 79 | let (left, right) = (self.find(left), self.find(right)); 80 | if left == right { return; } 81 | 82 | match (self.terminals.get(&left), self.terminals.get(&right)) { 83 | (Some(Integral(left_size)), Some(Integral(right_size))) => { 84 | let maximum = std::cmp::max(left_size.node, right_size.node); 85 | let left_node = S::new(maximum, left_size.span.clone()); 86 | self.terminals.insert(left, Terminal::Integral(left_node)); 87 | self.parents.insert(right, left); 88 | self.terminals.remove(&right); 89 | } 90 | (Some(left), Some(right)) if Terminal::equal(context, left, right) => (), 91 | (Some(Terminal::Type(S { node: Type::Never, .. })), Some(_)) | 92 | (Some(_), Some(Terminal::Type(S { node: Type::Never, .. }))) => (), 93 | (Some(Terminal::Type(S { node: Type::Array(left, _left_size), .. })), 94 | Some(Array(right, _right_size))) => { 95 | // TODO: perform size equality check 96 | let left_span = left.span.clone(); 97 | let (left_node, right) = (left.clone(), right.clone()); 98 | let left_node = self.next_with(Terminal::Type(*left_node)); 99 | self.unify(context, left_node, right, &left_span, right_span); 100 | } 101 | (Some(Terminal::Type(S { node: Type::Slice(left), .. })), Some(Slice(right))) | 102 | (Some(Terminal::Type(S { node: Type::Pointer(left), .. })), Some(Pointer(right))) => { 103 | let left_span = left.span.clone(); 104 | let (left_node, right) = (left.clone(), right.clone()); 105 | let left_node = self.next_with(Terminal::Type(*left_node)); 106 | self.unify(context, left_node, right, &left_span, right_span); 107 | } 108 | (Some(Terminal::Type(S { node: Type::Signed(_), .. })), Some(Integral(_))) | 109 | (Some(Terminal::Type(S { node: Type::Unsigned(_), .. })), Some(Integral(_))) => { 110 | let terminal = self.terminals.get(&left).cloned(); 111 | self.terminals.insert(right, terminal.unwrap()); 112 | } 113 | (Some(Slice(left)), Some(Slice(right))) | 114 | (Some(Sequence(left)), Some(Slice(right))) | 115 | (Some(Sequence(left)), Some(Array(right, _))) | 116 | (Some(Sequence(left)), Some(Sequence(right))) | 117 | (Some(Pointer(left)), Some(Pointer(right))) => { 118 | let (left, right) = (left.clone(), right.clone()); 119 | self.unify(context, left, right, left_span, right_span) 120 | } 121 | (Some(Array(left, left_size)), Some(Array(right, right_size))) 122 | if left_size == right_size => { 123 | let (left, right) = (left.clone(), right.clone()); 124 | self.unify(context, left, right, left_span, right_span) 125 | } 126 | (Some(Pointer(_)), Some(Terminal::Type(_))) | 127 | (Some(Integral(_)), Some(Terminal::Type(_))) | 128 | (Some(Array(_, _)), _) | (Some(Slice(_)), _) => 129 | self.unify(context, right, left, right_span, left_span), 130 | (Some(left), Some(right)) => { 131 | self.failure = true; 132 | context.emit(Diagnostic::error() 133 | .label(left_span.label().with_message(left.to_string())) 134 | .label(right_span.label().with_message(right.to_string())) 135 | .message("conflicting types")) 136 | } 137 | (Some(_), None) => { self.parents.insert(right, left); } 138 | (None, Some(_)) => { self.parents.insert(left, right); } 139 | (None, None) => { self.parents.insert(left, right); } 140 | } 141 | } 142 | 143 | pub fn find(&mut self, variable: TypeVariable) -> TypeVariable { 144 | match self.parents.get(&variable).cloned() { 145 | None => return variable, 146 | Some(parent) => { 147 | let root = self.find(parent); 148 | *self.parents.entry(variable).insert(root).get() 149 | } 150 | } 151 | } 152 | 153 | pub fn ascribe(&mut self, value: &ValueIndex, node: S) -> TypeVariable { 154 | self.terminal(value, Terminal::Type(node)) 155 | } 156 | 157 | pub fn terminal(&mut self, value: &ValueIndex, terminal: Terminal) -> TypeVariable { 158 | assert!(!self.values.contains_key(&value)); 159 | let variable = self.next_with(terminal); 160 | self.values.insert(*value, variable); 161 | variable 162 | } 163 | 164 | pub fn resolve(&mut self, variable: TypeVariable) -> Option> { 165 | let root = &self.find(variable); 166 | Some(match self.terminals.get(root)?.clone() { 167 | Terminal::Type(node) => node.clone(), 168 | Terminal::Pointer(node) => { 169 | let node = self.resolve(node)?; 170 | let span = node.span.clone(); 171 | S::new(Type::Pointer(Box::new(node)), span) 172 | } 173 | Terminal::Slice(node) => { 174 | let node = self.resolve(node)?; 175 | let span = node.span.clone(); 176 | S::new(Type::Slice(Box::new(node)), span) 177 | } 178 | Terminal::Array(node, size) => { 179 | let node = self.resolve(node)?; 180 | let span = node.span.clone(); 181 | let mut value = Value::default(); 182 | let size = ValueNode::Integral(size as i128); 183 | value.root = value.insert(S::new(size, span.clone())); 184 | S::new(Type::Array(Box::new(node), value), span) 185 | } 186 | Terminal::Integral(size) => 187 | S::new(Type::Signed(size.node), size.span), 188 | Terminal::Sequence(_) => return None, 189 | }) 190 | } 191 | } 192 | 193 | -------------------------------------------------------------------------------- /src/inference/structure.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::context::Context; 4 | use crate::error::Diagnostic; 5 | use crate::inference::Terminal; 6 | use crate::node::{Identifier, Path, Type, Value, ValueIndex}; 7 | use crate::query::QueryError; 8 | use crate::span::{S, Span}; 9 | 10 | use super::{Scene, TypeVariable}; 11 | 12 | pub fn field(context: &Context, scene: &mut Scene, place: Option<&S>, 13 | value: &Value, index: &ValueIndex, node: &ValueIndex, 14 | field: &S) -> crate::Result { 15 | let span = &value[*index].span; 16 | let node = super::value(context, scene, place, value, node)?; 17 | let node = scene.resolve(node).ok_or_else(|| 18 | context.error(Diagnostic::error().label(span.label()) 19 | .message("unresolved type").note("add a type annotation")))?; 20 | 21 | match &node.node { 22 | Type::Structure(path) => { 23 | let data = context.structures.get(path); 24 | let data = data.as_ref().ok_or(QueryError::Failure)?; 25 | match data.fields.get(&field.node) { 26 | None => context.pass(Diagnostic::error() 27 | .message(format!("structure has no field: {}", field)) 28 | .label(field.span.label())), 29 | Some(field) => Ok(scene.ascribe(index, field.clone())), 30 | } 31 | } 32 | other => context.pass(Diagnostic::error() 33 | .label(span.label().with_message(other.to_string())) 34 | .message("type is not a structure")), 35 | } 36 | } 37 | 38 | pub fn create(context: &Context, scene: &mut Scene, place: Option<&S>, 39 | value: &Value, index: &ValueIndex, fields: &HashMap, 40 | path: &S) -> crate::Result { 41 | let data = context.structures.get(&path.node); 42 | let data = data.as_ref().ok_or(QueryError::Failure)?; 43 | fields.iter().map(|(field, (_, span))| (field, span)) 44 | .filter(|(field, _)| !data.fields.contains_key(*field)) 45 | .try_for_each(|(_, span)| context.pass(Diagnostic::error() 46 | .message("field not in structure").label(span.label())))?; 47 | 48 | for (field, node) in &data.fields { 49 | if let Some((other, span)) = fields.get(field) { 50 | let other = super::value(context, scene, place, value, other)?; 51 | let node_type = scene.next_with(Terminal::Type(node.clone())); 52 | scene.unify(context, other, node_type, span, &node.span); 53 | } 54 | } 55 | 56 | let node = Type::Structure(path.node.clone()); 57 | Ok(scene.ascribe(index, S::new(node, path.span.clone()))) 58 | } 59 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(option_unwrap_none)] 2 | #![feature(entry_insert)] 3 | #![feature(never_type)] 4 | #![feature(concat_idents)] 5 | #![feature(bindings_after_at)] 6 | #![feature(array_value_iter)] 7 | #![feature(bool_to_option)] 8 | 9 | mod error; 10 | mod other; 11 | mod context; 12 | mod inference; 13 | mod generate; 14 | mod analysis; 15 | mod binary; 16 | mod arena; 17 | mod query; 18 | mod parse; 19 | mod node; 20 | mod span; 21 | 22 | type Result = std::result::Result; 23 | 24 | fn main() -> std::result::Result<(), Box> { 25 | let context = &context::Context::default(); 26 | let path = std::path::Path::new("examples/structures.lc"); 27 | query::emit(context, execute(context, path)); 28 | Ok(context::display(context)?) 29 | } 30 | 31 | fn execute(context: &context::Context, path: &std::path::Path) -> Result<()> { 32 | parse::parse(context, path)?; 33 | node::positions(context); 34 | node::present_all(context)?; 35 | binary::compile(context) 36 | } 37 | -------------------------------------------------------------------------------- /src/node/address.rs: -------------------------------------------------------------------------------- 1 | use crate::context::Context; 2 | use crate::error::Diagnostic; 3 | use crate::query::Key; 4 | use crate::span::{S, Span}; 5 | 6 | use super::{FunctionPath, Identifier, Symbol}; 7 | 8 | pub type Address = usize; 9 | pub type SymbolSize = usize; 10 | 11 | pub fn load(context: &Context, parent: Option, symbol: &Symbol, 12 | span: Option) -> crate::Result
{ 13 | let key = Key::LoadAddress(symbol.clone()); 14 | context.address.scope(parent, key.clone(), span.clone(), || { 15 | let targets = &[Identifier("load".to_string())]; 16 | let annotation = annotation(context, symbol, targets); 17 | if let Some(_annotation) = annotation { 18 | // TODO: load annotation address 19 | return Ok(1024 * 1024); 20 | } 21 | 22 | let span = self::span(context, symbol); 23 | let other = &previous(context, Some(key.clone()), 24 | symbol, targets, Some(span.clone()))? 25 | .ok_or_else(|| context.error(Diagnostic::error() 26 | .message("unable to derive load address") 27 | .note("add an annotation: @load
") 28 | .label(span.label())))?; 29 | 30 | let base = load(context, Some(key.clone()), other, Some(span.clone()))?; 31 | if let Symbol::Module(_) = other { return Ok(base); } 32 | let size = size(context, Some(key), other, Some(span))?; 33 | Ok(align(other, symbol, base + size)) 34 | }).map(|address| *address) 35 | } 36 | 37 | pub fn start(context: &Context, parent: Option, symbol: &Symbol, 38 | span: Option) -> crate::Result
{ 39 | let key = Key::VirtualAddress(symbol.clone()); 40 | context.address.scope(parent, key.clone(), span.clone(), || { 41 | let load = Identifier("load".to_string()); 42 | let targets = &[Identifier("virtual".to_string()), load]; 43 | let annotation = annotation(context, symbol, targets); 44 | if let Some(_annotation) = annotation { 45 | // TODO: load annotation address 46 | return Ok(1024 * 1024); 47 | } 48 | 49 | let span = Some(self::span(context, symbol)); 50 | let previous = previous(context, Some(key.clone()), 51 | symbol, targets, span.clone())?; 52 | let other = match previous.as_ref() { 53 | None => return self::load(context, 54 | Some(key.clone()), symbol, span), 55 | Some(previous) => previous, 56 | }; 57 | 58 | let base = start(context, Some(key.clone()), other, span.clone())?; 59 | if let Symbol::Module(_) = other { return Ok(base); } 60 | let size = size(context, Some(key), other, span)?; 61 | Ok(align(other, symbol, base + size)) 62 | }).map(|address| *address) 63 | } 64 | 65 | pub fn end(context: &Context, parent: Option, symbol: &Symbol, 66 | span: Option) -> crate::Result
{ 67 | let base = start(context, parent.clone(), symbol, span.clone())?; 68 | Ok(base + size(context, parent, symbol, span)?) 69 | } 70 | 71 | pub fn size(context: &Context, parent: Option, symbol: &Symbol, 72 | span: Option) -> crate::Result { 73 | let key = Key::SymbolSize(symbol.clone()); 74 | context.address.scope(parent, key.clone(), 75 | span.clone(), || match symbol { 76 | Symbol::Variable(path) => { 77 | let path = crate::inference::type_variable(context, 78 | Some(key.clone()), path.clone(), span.clone())?; 79 | super::size(context, Some(key), &path.node, span) 80 | } 81 | // TODO: use architecture generation 82 | Symbol::Function(path) => Ok(crate::generate::x86::lower(context, 83 | Some(key.clone()), path, span)?.bytes.len()), 84 | Symbol::Module(path) => { 85 | let module = context.modules.get(path).unwrap(); 86 | Iterator::zip(module.first.iter(), module.last.iter()).map(|(first, last)| { 87 | let start = start(context, Some(key.clone()), first, span.clone())?; 88 | Ok(end(context, Some(key.clone()), last, span.clone())? - start) 89 | }).next().transpose().map(Option::unwrap_or_default) 90 | } 91 | }).map(|size| *size) 92 | } 93 | 94 | fn align(other: &Symbol, symbol: &Symbol, address: Address) -> Address { 95 | match (other, symbol) { 96 | (Symbol::Function(_), Symbol::Function(_)) => address, 97 | (Symbol::Variable(_), Symbol::Variable(_)) => address, 98 | _ => { 99 | // TODO: derive alignment from annotation 100 | let alignment = 4 * 1024; 101 | crate::other::ceiling(address, alignment) 102 | } 103 | } 104 | } 105 | 106 | fn span(context: &Context, symbol: &Symbol) -> Span { 107 | match symbol { 108 | Symbol::Function(FunctionPath(path, kind)) => 109 | context.functions.get(path).unwrap()[*kind] 110 | .identifier.span.clone(), 111 | Symbol::Variable(path) => context.statics.get(path) 112 | .unwrap().identifier.span.clone(), 113 | Symbol::Module(path) => context.modules.get(path) 114 | .unwrap().identifier.span.clone(), 115 | } 116 | } 117 | 118 | fn annotation(context: &Context, symbol: &Symbol, 119 | targets: &[Identifier]) -> Option> { 120 | targets.iter().find_map(|target| match symbol { 121 | Symbol::Function(FunctionPath(path, kind)) => 122 | context.functions.get(path).unwrap()[*kind] 123 | .annotations.get(target).cloned(), 124 | Symbol::Variable(path) => context.statics.get(path) 125 | .unwrap().annotations.get(target).cloned(), 126 | Symbol::Module(path) => context.modules.get(path) 127 | .unwrap().annotations.get(target).cloned(), 128 | }) 129 | } 130 | 131 | fn previous(context: &Context, parent: Option, symbol: &Symbol, 132 | targets: &[Identifier], span: Option) -> crate::Result> { 133 | let positions = context.positions.read(); 134 | let position = &positions[symbol]; 135 | match &position.previous { 136 | Some(symbol) => find(context, parent, symbol, targets, span), 137 | None => position.parent.as_ref() 138 | .map(|path| match targets.iter().any(|target| context.modules 139 | .get(path).unwrap().annotations.contains_key(target)) { 140 | false => previous(context, parent, 141 | &Symbol::Module(path.clone()), targets, span), 142 | true => Ok(Some(Symbol::Module(path.clone()))), 143 | }).transpose().map(Option::flatten), 144 | } 145 | } 146 | 147 | fn find(context: &Context, parent: Option, symbol: &Symbol, 148 | targets: &[Identifier], span: Option) -> crate::Result> { 149 | if let Symbol::Module(path) = symbol { 150 | let module = context.modules.get(path).unwrap(); 151 | let contains = |target| !module.annotations.contains_key(target); 152 | if targets.iter().any(contains) { 153 | if let Some(last) = module.last.as_ref() { 154 | return find(context, parent, last, targets, span); 155 | } 156 | } 157 | } 158 | 159 | match symbol { 160 | Symbol::Function(function @ FunctionPath(path, kind)) if 161 | super::present(context, parent.clone(), function, span.clone())? 162 | && targets.iter().any(|target| !context.functions.get(path).unwrap()[*kind] 163 | .annotations.contains_key(target)) => return Ok(Some(symbol.clone())), 164 | Symbol::Variable(path) if targets.iter().any(|target| context.statics.get(path) 165 | .unwrap().annotations.contains_key(target)) => return Ok(Some(symbol.clone())), 166 | _ => previous(context, parent, symbol, targets, span), 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/node/context.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::context::Context; 4 | use crate::node::{Function, FunctionPath}; 5 | use crate::query::{Key, QueryError}; 6 | use crate::span::Span; 7 | 8 | pub fn function(context: &Context, parent: Option, path: &FunctionPath, 9 | span: Option) -> crate::Result> { 10 | let FunctionPath(function, kind) = path; 11 | let functions = context.functions.get(&function); 12 | let function = functions.as_ref().and_then(|table| 13 | table.get(*kind).cloned()).ok_or(QueryError::Failure)?; 14 | crate::analysis::function(context, parent, path, &function, span)?; 15 | Ok(function) 16 | } 17 | -------------------------------------------------------------------------------- /src/node/function.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::fmt; 3 | use std::ops::Index; 4 | 5 | use crate::context::Context; 6 | use crate::span::{S, Span}; 7 | 8 | use super::{Identifier, Path}; 9 | 10 | pub type ValueIndex = usize; 11 | 12 | #[derive(Debug, Default, Clone)] 13 | pub struct Value { 14 | pub root: ValueIndex, 15 | pub values: Vec>, 16 | } 17 | 18 | impl Value { 19 | pub fn insert(&mut self, node: S) -> ValueIndex { 20 | let index = self.values.len(); 21 | self.values.push(node); 22 | index 23 | } 24 | } 25 | 26 | impl Index for Value { 27 | type Output = S; 28 | 29 | fn index(&self, index: usize) -> &Self::Output { 30 | self.values.get(index).unwrap_or_else(|| 31 | panic!("value index: {}, is invalid", index)) 32 | } 33 | } 34 | 35 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 36 | pub struct Variable(pub Identifier, pub u16); 37 | 38 | #[derive(Debug, Clone)] 39 | pub enum ValueNode { 40 | Block(Vec), 41 | Let(S, Option>, Option), 42 | Set(ValueIndex, ValueIndex), 43 | While(ValueIndex, ValueIndex), 44 | When(Vec<(ValueIndex, ValueIndex)>), 45 | Cast(ValueIndex, S), 46 | Return(Option), 47 | // TODO: move compile to separate value 48 | Compile(ValueIndex), 49 | Inline(ValueIndex), 50 | Call(S, Vec), 51 | Field(ValueIndex, S), 52 | Create(S, HashMap), 53 | Slice(ValueIndex, Option, Option), 54 | Index(ValueIndex, ValueIndex), 55 | Compound(Dual, ValueIndex, ValueIndex), 56 | Binary(Binary, ValueIndex, ValueIndex), 57 | Unary(Unary, ValueIndex), 58 | Variable(Variable), 59 | Path(Path), 60 | String(String), 61 | Register(Identifier), 62 | Array(Vec), 63 | Integral(i128), 64 | Truth(bool), 65 | Rune(char), 66 | Continue, 67 | Break, 68 | } 69 | 70 | #[derive(Debug, Clone)] 71 | pub enum Type { 72 | Void, 73 | Rune, 74 | Truth, 75 | Never, 76 | Structure(Path), 77 | Signed(Size), 78 | Unsigned(Size), 79 | Pointer(Box>), 80 | Array(Box>, Value), 81 | Slice(Box>), 82 | } 83 | 84 | impl Type { 85 | pub fn composite(&self) -> bool { 86 | match self { 87 | Type::Array(_, _) | Type::Slice(_) | 88 | Type::Structure(_) => true, 89 | _ => false, 90 | } 91 | } 92 | 93 | pub fn equal(context: &Context, left: &Self, right: &Self) -> bool { 94 | use Type::*; 95 | match (left, right) { 96 | (Void, Void) => true, 97 | (Rune, Rune) => true, 98 | (Truth, Truth) => true, 99 | (Never, Never) => true, 100 | (Structure(left), Structure(right)) => left == right, 101 | (Signed(left), Signed(right)) => left == right, 102 | (Unsigned(left), Unsigned(right)) => left == right, 103 | (Pointer(left), Pointer(right)) => Type::equal(context, &left.node, &right.node), 104 | // TODO: perform array size evaluations 105 | (Array(left, _), Array(right, _)) => Type::equal(context, &left.node, &right.node), 106 | (Slice(left), Slice(right)) => Type::equal(context, &left.node, &right.node), 107 | _ => false, 108 | } 109 | } 110 | } 111 | 112 | impl fmt::Display for Type { 113 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 114 | match self { 115 | Type::Void => write!(f, "void"), 116 | Type::Rune => write!(f, "rune"), 117 | Type::Truth => write!(f, "truth"), 118 | Type::Never => write!(f, "never"), 119 | Type::Structure(path) => write!(f, "{}", path), 120 | Type::Signed(size) => write!(f, "i{}", size), 121 | Type::Unsigned(size) => write!(f, "u{}", size), 122 | Type::Pointer(node) => write!(f, "*{}", node), 123 | Type::Array(node, value) => match value[value.root].node { 124 | ValueNode::Integral(size) => write!(f, "[{}; {}]", node, size), 125 | _ => write!(f, "[{}; _]", node), 126 | } 127 | Type::Slice(node) => write!(f, "[{};]", node), 128 | } 129 | } 130 | } 131 | 132 | #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] 133 | pub enum Size { 134 | Byte = 8, 135 | Word = 16, 136 | Double = 32, 137 | Quad = 64, 138 | } 139 | 140 | impl Size { 141 | pub fn bytes(self) -> usize { 142 | (self as usize) / 8 143 | } 144 | } 145 | 146 | impl fmt::Display for Size { 147 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 148 | write!(f, "{}", *self as usize) 149 | } 150 | } 151 | 152 | #[derive(Debug, Copy, Clone)] 153 | pub enum Binary { 154 | Dual(Dual), 155 | Compare(Compare), 156 | And, 157 | Or, 158 | } 159 | 160 | impl Binary { 161 | pub fn parse(string: &str) -> Option { 162 | Some(match string { 163 | "||" => Binary::Or, 164 | "&&" => Binary::And, 165 | "==" => Binary::Compare(Compare::Equal), 166 | "!=" => Binary::Compare(Compare::NotEqual), 167 | "<" => Binary::Compare(Compare::Less), 168 | ">" => Binary::Compare(Compare::Greater), 169 | "<=" => Binary::Compare(Compare::LessEqual), 170 | ">=" => Binary::Compare(Compare::GreaterEqual), 171 | _ => Binary::Dual(Dual::parse(string)?), 172 | }) 173 | } 174 | } 175 | 176 | #[derive(Debug, Copy, Clone, PartialEq)] 177 | pub enum Dual { 178 | Add, 179 | Minus, 180 | Multiply, 181 | Divide, 182 | Modulo, 183 | BinaryOr, 184 | BinaryAnd, 185 | ExclusiveOr, 186 | ShiftLeft, 187 | ShiftRight, 188 | } 189 | 190 | impl Dual { 191 | pub fn parse(string: &str) -> Option { 192 | Some(match string { 193 | "+" => Dual::Add, 194 | "-" => Dual::Minus, 195 | "*" => Dual::Multiply, 196 | "/" => Dual::Divide, 197 | "%" => Dual::Modulo, 198 | "&" => Dual::BinaryAnd, 199 | "^" => Dual::ExclusiveOr, 200 | "|" => Dual::BinaryOr, 201 | "<<" => Dual::ShiftLeft, 202 | ">>" => Dual::ShiftRight, 203 | _ => return None, 204 | }) 205 | } 206 | } 207 | 208 | #[derive(Debug, Copy, Clone)] 209 | pub enum Compare { 210 | Less, 211 | Greater, 212 | LessEqual, 213 | GreaterEqual, 214 | NotEqual, 215 | Equal, 216 | } 217 | 218 | #[derive(Debug, Copy, Clone)] 219 | pub enum Unary { 220 | Not, 221 | Negate, 222 | Reference, 223 | Dereference, 224 | } 225 | -------------------------------------------------------------------------------- /src/node/item.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::fmt; 3 | 4 | use indexmap::IndexMap; 5 | 6 | use crate::node::Variable; 7 | use crate::span::S; 8 | 9 | #[derive(Debug)] 10 | pub enum Item { 11 | Symbol(Symbol), 12 | ModuleEnd, 13 | } 14 | 15 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 16 | pub enum Symbol { 17 | Module(Path), 18 | Variable(Path), 19 | Function(FunctionPath), 20 | } 21 | 22 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 23 | pub struct Identifier(pub String); 24 | 25 | impl fmt::Display for Identifier { 26 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 27 | let Identifier(identifier) = self; 28 | write!(f, "{}", identifier) 29 | } 30 | } 31 | 32 | #[derive(Default, Clone, Hash, Eq, PartialEq)] 33 | pub struct Path(pub Vec); 34 | 35 | impl Path { 36 | #[must_use] 37 | pub fn push(&self, identifier: Identifier) -> Path { 38 | let Path(mut path) = self.clone(); 39 | path.push(identifier); 40 | Self(path) 41 | } 42 | } 43 | 44 | impl PartialEq<[&str]> for Path { 45 | fn eq(&self, other: &[&str]) -> bool { 46 | let Path(elements) = self; 47 | elements.len() == other.len() && 48 | Iterator::zip(elements.iter(), other) 49 | .all(|(Identifier(left), right)| left == right) 50 | } 51 | } 52 | 53 | impl fmt::Display for Path { 54 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 55 | let Path(path) = self; 56 | let (last, slice) = path.split_last().unwrap(); 57 | slice.iter().try_for_each(|identifier| write!(f, "{}.", identifier))?; 58 | write!(f, "{}", last) 59 | } 60 | } 61 | 62 | impl fmt::Debug for Path { 63 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 64 | write!(f, "{}", self) 65 | } 66 | } 67 | 68 | pub type Annotations = HashMap>; 69 | 70 | #[derive(Debug)] 71 | pub struct Structure { 72 | pub annotations: Annotations, 73 | pub fields: IndexMap>, 74 | } 75 | 76 | #[derive(Debug)] 77 | pub struct Static { 78 | pub annotations: Annotations, 79 | pub identifier: S, 80 | pub node_type: Option>, 81 | pub value: Option, 82 | } 83 | 84 | pub type FunctionKind = usize; 85 | 86 | #[derive(Debug, Default, Clone, Hash, Eq, PartialEq)] 87 | pub struct FunctionPath(pub Path, pub FunctionKind); 88 | 89 | #[derive(Debug)] 90 | pub struct Function { 91 | pub is_root: bool, 92 | pub annotations: Annotations, 93 | pub identifier: S, 94 | pub convention: Option>, 95 | pub parameters: Vec>, 96 | pub return_type: S, 97 | pub value: super::Value, 98 | } 99 | 100 | #[derive(Debug, Clone)] 101 | pub enum ReturnType { 102 | Register(S), 103 | Type(S), 104 | } 105 | 106 | #[derive(Debug, Clone)] 107 | pub enum Parameter { 108 | Register(S), 109 | Variable(S, S), 110 | } 111 | 112 | #[derive(Debug)] 113 | pub struct Module { 114 | pub annotations: Annotations, 115 | pub identifier: S, 116 | pub first: Option, 117 | pub last: Option, 118 | } 119 | -------------------------------------------------------------------------------- /src/node/mod.rs: -------------------------------------------------------------------------------- 1 | pub use context::*; 2 | pub use function::*; 3 | pub use item::*; 4 | pub use offsets::*; 5 | pub use position::*; 6 | pub use present::*; 7 | 8 | pub mod address; 9 | 10 | mod offsets; 11 | mod function; 12 | mod position; 13 | mod present; 14 | mod context; 15 | mod item; 16 | -------------------------------------------------------------------------------- /src/node/offsets.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::sync::Arc; 3 | 4 | use crate::context::Context; 5 | use crate::node::{Identifier, Path, Size, Type}; 6 | use crate::query::{Key, QueryError}; 7 | use crate::span::Span; 8 | 9 | #[derive(Debug, Default)] 10 | pub struct Offsets { 11 | pub fields: HashMap, 12 | pub size: usize, 13 | } 14 | 15 | pub fn size(context: &Context, parent: Option, path: &Type, 16 | span: Option) -> crate::Result { 17 | Ok(match path { 18 | Type::Void | Type::Never => 0, 19 | Type::Truth => Size::Byte.bytes(), 20 | Type::Rune => Size::Double.bytes(), 21 | Type::Structure(path) => offsets(context, parent, path, span)?.size, 22 | Type::Signed(size) | Type::Unsigned(size) => size.bytes(), 23 | // TODO: dependent on architecture 24 | Type::Pointer(_) => unimplemented!(), 25 | // TODO: dependent on compile time evaluation 26 | Type::Array(_, _) => unimplemented!(), 27 | // TODO: dependent on pointer size 28 | Type::Slice(_) => unimplemented!(), 29 | }) 30 | } 31 | 32 | pub fn offset(context: &Context, parent: Option, path: &Type, 33 | field: &Identifier, span: Option) -> crate::Result { 34 | Ok(match path { 35 | Type::Structure(path) => offsets(context, 36 | parent, path, span)?.fields[field], 37 | Type::Slice(_) => { 38 | // TODO: dependent on pointer size 39 | unimplemented!() 40 | } 41 | other => panic!("offset on type: {}", other), 42 | }) 43 | } 44 | 45 | // TODO: consider C and packed representation 46 | pub fn offsets(context: &Context, parent: Option, path: &Path, 47 | span: Option) -> crate::Result> { 48 | let key = Key::Offsets(path.clone()); 49 | context.offsets.scope(parent, key.clone(), span, || { 50 | let mut offsets = Offsets::default(); 51 | let structure = context.structures.get(&path) 52 | .ok_or(QueryError::Failure)?; 53 | 54 | for (field, path) in &structure.fields { 55 | offsets.fields.insert(field.clone(), offsets.size); 56 | offsets.size += size(context, Some(key.clone()), 57 | &path.node, Some(path.span.clone()))?; 58 | } 59 | 60 | Ok(offsets) 61 | }) 62 | } 63 | 64 | -------------------------------------------------------------------------------- /src/node/position.rs: -------------------------------------------------------------------------------- 1 | use crate::context::Context; 2 | use crate::node::{Item, Path}; 3 | 4 | use super::Symbol; 5 | 6 | #[derive(Debug, Default, Clone)] 7 | pub struct Position { 8 | pub parent: Option, 9 | pub previous: Option, 10 | } 11 | 12 | pub fn positions(context: &Context) { 13 | let mut stack = Vec::new(); 14 | stack.push(Position::default()); 15 | let items = context.items.read(); 16 | items.iter().for_each(|item| match item { 17 | Item::Symbol(symbol) => { 18 | if let Some(module) = &stack.last().unwrap().parent { 19 | let module = &mut context.modules.get_mut(module).unwrap(); 20 | if module.first.is_none() { module.first = Some(symbol.clone()); } 21 | module.last = Some(symbol.clone()); 22 | } 23 | 24 | match symbol { 25 | Symbol::Function(_) | Symbol::Variable(_) => { 26 | let position = stack.last().unwrap().clone(); 27 | context.positions.write().insert(symbol.clone(), position); 28 | stack.last_mut().unwrap().previous = Some(symbol.clone()); 29 | } 30 | Symbol::Module(path) => { 31 | let parent = Some(path.clone()); 32 | stack.push(Position { parent, previous: None }); 33 | } 34 | } 35 | } 36 | Item::ModuleEnd => { 37 | let path = Symbol::Module(stack.pop().unwrap().parent.unwrap()); 38 | context.positions.write().insert(path.clone(), stack.last().unwrap().clone()); 39 | stack.last_mut().unwrap().previous = Some(path); 40 | } 41 | }) 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/node/present.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashSet; 2 | 3 | use crate::context::Context; 4 | use crate::query::Key; 5 | use crate::span::Span; 6 | 7 | use super::{FunctionPath, ValueNode}; 8 | 9 | pub fn present_all(context: &Context) -> crate::Result<()> { 10 | let mut present = HashSet::new(); 11 | context.unit.ephemeral(None, Key::TraverseRoots, None, || context.functions.iter() 12 | .try_for_each(|path| path.value().iter().filter(|function| function.is_root) 13 | .enumerate().map(|(kind, _)| FunctionPath(path.key().clone(), kind)) 14 | .try_for_each(|path| Ok(if !present.contains(&path) { 15 | present.insert(path.clone()); 16 | self::function(context, &mut present, &path)? 17 | })))).map(|_| *context.present.write() = present) 18 | } 19 | 20 | pub fn present(context: &Context, parent: Option, path: &FunctionPath, 21 | span: Option) -> crate::Result { 22 | let mut present = false; 23 | context.unit.ephemeral(parent, Key::TraverseRoots, span, 24 | || Ok(present = context.present.read().contains(path)))?; 25 | Ok(present) 26 | } 27 | 28 | fn function(context: &Context, present: &mut HashSet, 29 | path: &FunctionPath) -> crate::Result<()> { 30 | let function = crate::node::function(context, None, path, None)?; 31 | let types = crate::inference::type_function(context, None, path, None)?; 32 | types.functions.iter().try_for_each(|(index, kind)| { 33 | let path = match &function.value[*index].node { 34 | ValueNode::Call(path, _) => path.clone(), 35 | _ => panic!("value: {}, is not a function call", index), 36 | }; 37 | 38 | let function = FunctionPath(path.node, *kind); 39 | Ok(if !present.contains(&function) { 40 | present.insert(function.clone()); 41 | self::function(context, present, &function)?; 42 | }) 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /src/other.rs: -------------------------------------------------------------------------------- 1 | pub fn ceiling(value: usize, multiple: usize) -> usize { 2 | if value % multiple == 0 { return value; } 3 | let padding = multiple - (value % multiple); 4 | value + padding 5 | } 6 | -------------------------------------------------------------------------------- /src/parse/function.rs: -------------------------------------------------------------------------------- 1 | use tree_sitter::Node; 2 | 3 | use crate::context::Context; 4 | use crate::error::Diagnostic; 5 | use crate::node::{Function, Identifier, Parameter, ReturnType, Size, Type}; 6 | use crate::parse::Scene; 7 | use crate::span::S; 8 | 9 | use super::{Source, SymbolKind, Symbols}; 10 | 11 | pub fn function(context: &Context, symbols: &mut Symbols, 12 | source: &Source, node: Node) -> crate::Result { 13 | let identifier = super::field_identifier(source, node); 14 | let annotations = super::annotations(context, symbols, source, node); 15 | let is_root = node.child_by_field_name("root").is_some(); 16 | let mut scene = Scene::new(context, symbols, source); 17 | 18 | let parameters = parameters(&mut scene, node)?; 19 | let return_type = return_type(&mut scene, node, &identifier)?; 20 | let convention = node.child_by_field_name("convention") 21 | .map(|node| super::identifier(source, node)); 22 | 23 | let value = node.child_by_field_name("block").unwrap(); 24 | scene.value.root = super::unit(&mut scene, value)?; 25 | let value = scene.value; 26 | 27 | Ok(Function { 28 | is_root, 29 | convention, 30 | annotations, 31 | parameters, 32 | return_type, 33 | value, 34 | identifier, 35 | }) 36 | } 37 | 38 | fn parameters(scene: &mut Scene, node: Node) -> crate::Result>> { 39 | let cursor = &mut node.walk(); 40 | node.children_by_field_name("parameter", cursor) 41 | .map(|node| Ok(S::create(match node.kind() { 42 | "register" => Parameter::Register(super::register(scene.source, node)), 43 | "parameter" => { 44 | let identifier = super::field_identifier(scene.source, node); 45 | match scene.generations.contains_key(&identifier.node) { 46 | true => scene.context.pass(Diagnostic::error() 47 | .message("duplicate parameter").label(identifier.span.label()))?, 48 | false => { 49 | let node_type = node_type(scene.context, scene.symbols, 50 | scene.source, node.child_by_field_name("type").unwrap())?; 51 | Parameter::Variable(scene.binding(identifier), node_type) 52 | } 53 | } 54 | } 55 | other => panic!("invalid parameter type: {}", other), 56 | }, node.byte_range(), scene.source.file))).collect() 57 | } 58 | 59 | fn return_type(scene: &mut Scene, node: Node, identifier: &S) 60 | -> crate::Result> { 61 | Ok(node.child_by_field_name("return") 62 | .map(|node| Ok(S::create(match node.kind() { 63 | "register" => ReturnType::Register(super::register(scene.source, node)), 64 | _ => ReturnType::Type(node_type(scene.context, 65 | scene.symbols, scene.source, node)?), 66 | }, node.byte_range(), scene.source.file))).transpose()? 67 | .unwrap_or_else(|| { 68 | let void = S::new(Type::Void, identifier.span.clone()); 69 | S::new(ReturnType::Type(void), identifier.span.clone()) 70 | })) 71 | } 72 | 73 | pub fn node_type(context: &Context, symbols: &Symbols, 74 | source: &Source, node: Node) -> crate::Result> { 75 | Ok(S::create(match node.kind() { 76 | "pointer" => { 77 | let node = node_type(context, symbols, 78 | source, node.named_child(0).unwrap())?; 79 | Type::Pointer(Box::new(node)) 80 | } 81 | "array_type" => { 82 | let element = node.child_by_field_name("type").unwrap(); 83 | let size = node.child_by_field_name("size").unwrap(); 84 | let size = super::value(context, symbols, source, size)?; 85 | let element = node_type(context, symbols, source, element)?; 86 | Type::Array(Box::new(element), size) 87 | } 88 | "slice_type" => { 89 | let element = node.child_by_field_name("type").unwrap(); 90 | let element = node_type(context, symbols, source, element)?; 91 | Type::Slice(Box::new(element)) 92 | } 93 | "path" => return path_type(context, source, symbols, node), 94 | other => panic!("invalid type kind: {}", other), 95 | }, node.byte_range(), source.file)) 96 | } 97 | 98 | fn path_type(context: &Context, source: &Source, symbols: &Symbols, 99 | node: Node) -> crate::Result> { 100 | let path = super::path(source, node); 101 | Ok(S::create(match path.to_string().as_str() { 102 | "rune" => Type::Rune, 103 | "truth" => Type::Truth, 104 | "never" => Type::Never, 105 | "i8" => Type::Signed(Size::Byte), 106 | "i16" => Type::Signed(Size::Word), 107 | "i32" => Type::Signed(Size::Double), 108 | "i64" => Type::Signed(Size::Quad), 109 | "u8" => Type::Unsigned(Size::Byte), 110 | "u16" => Type::Unsigned(Size::Word), 111 | "u32" => Type::Unsigned(Size::Double), 112 | "u64" => Type::Unsigned(Size::Quad), 113 | _ => match symbols.resolve(context, &path.node, &path.span) { 114 | Some((path, SymbolKind::Structure)) => Type::Structure(path), 115 | Some(_) => return context.pass(Diagnostic::error().label(path.span.label()) 116 | .message(format!("symbol at path: {}, is not a data structure", path))), 117 | None => return context.pass(Diagnostic::error().label(path.span.label()) 118 | .message(format!("no data structure at path: {}", path))), 119 | }, 120 | }, node.byte_range(), source.file)) 121 | } 122 | -------------------------------------------------------------------------------- /src/parse/item.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::path::PathBuf; 3 | use std::sync::Arc; 4 | 5 | use codespan::FileId; 6 | use indexmap::IndexMap; 7 | use tree_sitter::{Language, Node, Parser, Query}; 8 | 9 | use crate::context::Context; 10 | use crate::error::Diagnostic; 11 | use crate::node::*; 12 | use crate::parse::Include; 13 | use crate::span::S; 14 | 15 | use super::{Symbols, Unit}; 16 | 17 | extern { fn tree_sitter_lucent() -> Language; } 18 | 19 | #[derive(Debug, Clone)] 20 | pub struct Source { 21 | pub file: FileId, 22 | pub path: PathBuf, 23 | pub text: Arc, 24 | } 25 | 26 | pub fn parser() -> Parser { 27 | let mut parser = Parser::new(); 28 | let language = unsafe { tree_sitter_lucent() }; 29 | parser.set_language(language).unwrap(); 30 | parser 31 | } 32 | 33 | pub fn errors() -> Query { 34 | let language = unsafe { tree_sitter_lucent() }; 35 | Query::new(language, "(ERROR) @error").unwrap() 36 | } 37 | 38 | pub fn parse(context: &Context, path: &std::path::Path) -> crate::Result<()> { 39 | let (mut symbols, units) = Symbols::root(context, path)?; 40 | units.iter().map(|unit| match unit { 41 | Unit::Item(path, source, node) => self::item(context, 42 | &mut symbols, path.clone(), source, *node), 43 | Unit::ModuleEnd => { 44 | context.items.write().push(Item::ModuleEnd); 45 | Ok(symbols.pop()) 46 | } 47 | }).filter(Result::is_err).last().unwrap_or(Ok(())) 48 | } 49 | 50 | pub fn item(context: &Context, symbols: &mut Symbols, path: Path, 51 | source: &Source, node: Node) -> crate::Result<()> { 52 | Ok(match node.kind() { 53 | "function" => { 54 | let function = super::function(context, symbols, source, node)?; 55 | let functions = &mut context.functions.entry(path.clone()).or_default(); 56 | let symbol = Symbol::Function(FunctionPath(path, functions.len())); 57 | context.items.write().push(Item::Symbol(symbol)); 58 | functions.push(Arc::new(function)); 59 | } 60 | "static" => { 61 | let identifier = field_identifier(source, node); 62 | let node_type = node.child_by_field_name("type").map(|node| 63 | super::node_type(context, symbols, source, node)).transpose()?; 64 | let value = node.child_by_field_name("value").map(|node| 65 | super::value(context, symbols, source, node)).transpose()?; 66 | let annotations = annotations(context, symbols, source, node); 67 | let variable = Static { annotations, identifier, node_type, value }; 68 | 69 | let symbol = Symbol::Variable(path.clone()); 70 | context.items.write().push(Item::Symbol(symbol)); 71 | context.statics.insert(path, variable); 72 | } 73 | "use" => { 74 | let node_as = node.child_by_field_name("as"); 75 | let S { node: Path(mut elements), span } = self::path(source, 76 | node.child_by_field_name("path").unwrap()); 77 | 78 | symbols.include(S::create(match (elements.last().unwrap(), node_as) { 79 | (Identifier(string), Some(_)) if string == "*" => return 80 | context.pass(Diagnostic::error().label(span.label()) 81 | .message("wildcard imports cannot be aliased")), 82 | (Identifier(string), None) if string == "*" => { 83 | elements.pop(); 84 | Include::Wild(Path(elements)) 85 | } 86 | (_, Some(node_as)) => Include::As(Path(elements), 87 | identifier(source, node_as).node), 88 | (_, None) => Include::Item(Path(elements)), 89 | }, node.byte_range(), source.file)); 90 | } 91 | "data" => { 92 | let cursor = &mut node.walk(); 93 | let mut fields = IndexMap::new(); 94 | for node in node.children_by_field_name("field", cursor) { 95 | let identifier = field_identifier(source, node); 96 | let node_type = super::node_type(context, symbols, 97 | source, node.child_by_field_name("type").unwrap())?; 98 | match fields.get(&identifier.node) { 99 | None => fields.insert(identifier.node, node_type), 100 | Some(other) => return context.pass(Diagnostic::error() 101 | .label(other.span.label()).label(identifier.span.label()) 102 | .message("duplicate field")), 103 | }; 104 | } 105 | 106 | let annotations = annotations(context, symbols, source, node); 107 | context.structures.insert(path, Structure { annotations, fields }); 108 | } 109 | "module" => { 110 | let symbol = Symbol::Module(path.clone()); 111 | context.items.write().push(Item::Symbol(symbol)); 112 | 113 | let identifier = field_identifier(source, node); 114 | let annotations = annotations(context, symbols, source, node); 115 | let module = Module { annotations, identifier, first: None, last: None }; 116 | context.modules.insert(path.clone(), module); 117 | 118 | symbols.push(); 119 | symbols.include(S::create(Include::Wild(path), 120 | node.byte_range(), source.file)); 121 | } 122 | "annotation" => (), // TODO: implement global annotations 123 | other => panic!("invalid item kind: {}", other), 124 | }) 125 | } 126 | 127 | pub fn annotations(context: &Context, symbols: &Symbols, 128 | source: &Source, node: Node) -> Annotations { 129 | let cursor = &mut node.walk(); 130 | let mut annotations: Annotations = HashMap::new(); 131 | for node in node.children_by_field_name("annotation", cursor) { 132 | let name = node.child_by_field_name("name") 133 | .map(|node| identifier(source, node)).unwrap(); 134 | if let Some(other) = annotations.get(&name.node) { 135 | context.emit(Diagnostic::error().message("duplicate annotation") 136 | .label(other.span.label()).label(name.span.label())); 137 | } 138 | 139 | let value = super::value(context, symbols, source, 140 | node.child_by_field_name("value").unwrap()); 141 | if let Ok(value) = value { 142 | let value = S::new(value, name.span); 143 | annotations.insert(name.node, value); 144 | } 145 | } 146 | annotations 147 | } 148 | 149 | pub fn path(source: &Source, node: Node) -> S { 150 | let cursor = &mut node.walk(); 151 | S::create(Path(node.named_children(cursor) 152 | .map(|node| identifier(source, node).node) 153 | .collect()), node.byte_range(), source.file) 154 | } 155 | 156 | pub fn field_identifier(source: &Source, node: Node) -> S { 157 | identifier(source, node.child_by_field_name("identifier").unwrap()) 158 | } 159 | 160 | pub fn identifier(source: &Source, node: Node) -> S { 161 | let text = source.text[node.byte_range()].to_string(); 162 | S::create(Identifier(text), node.byte_range(), source.file) 163 | } 164 | 165 | pub fn register(source: &Source, node: Node) -> S { 166 | let text = source.text[node.byte_range()][1..].to_string(); 167 | S::create(Identifier(text), node.byte_range(), source.file) 168 | } 169 | 170 | pub fn string(source: &Source, node: Node) -> S { 171 | let text = &source.text[node.start_byte() + 1..node.end_byte() - 1]; 172 | S::create(text.to_string(), node.byte_range(), source.file) 173 | } 174 | -------------------------------------------------------------------------------- /src/parse/mod.rs: -------------------------------------------------------------------------------- 1 | pub use function::*; 2 | pub use item::*; 3 | pub use symbols::*; 4 | pub use value::*; 5 | 6 | mod item; 7 | mod symbols; 8 | mod function; 9 | mod value; 10 | -------------------------------------------------------------------------------- /src/parse/symbols.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use tree_sitter::{Node, Query, QueryCursor, Tree}; 4 | 5 | use crate::arena::OwnedArena; 6 | use crate::context::Context; 7 | use crate::error::Diagnostic; 8 | use crate::node::{Identifier, Path}; 9 | use crate::query::Key; 10 | use crate::span::{S, Span}; 11 | 12 | use super::Source; 13 | 14 | #[derive(Debug)] 15 | pub enum Include { 16 | Wild(Path), 17 | Item(Path), 18 | As(Path, Identifier), 19 | } 20 | 21 | #[derive(Debug, Clone, PartialEq)] 22 | pub enum SymbolKind { 23 | Function, 24 | Variable, 25 | Intrinsic, 26 | Structure, 27 | Library, 28 | Module, 29 | } 30 | 31 | pub enum Unit<'a> { 32 | Item(Path, Source, Node<'a>), 33 | ModuleEnd, 34 | } 35 | 36 | #[derive(Default)] 37 | pub struct Symbols<'a> { 38 | table: HashMap>, 39 | includes: Vec>>, 40 | trees: OwnedArena<'a, Tree>, 41 | } 42 | 43 | impl<'a> Symbols<'a> { 44 | pub fn root(context: &Context, path: &std::path::Path) 45 | -> crate::Result<(Self, Vec>)> { 46 | let mut units = Vec::new(); 47 | let mut symbols = Symbols { includes: vec![Vec::new()], ..Symbols::default() }; 48 | let internal = S::new(SymbolKind::Intrinsic, context.files.read().internal.clone()); 49 | ["size", "start", "end"].iter().map(|intrinsic| Identifier(intrinsic.to_string())) 50 | .map(|intrinsic| Path(vec![Identifier("Intrinsic".to_string()), intrinsic])) 51 | .for_each(|path| symbols.table.insert(path, internal.clone()).unwrap_none()); 52 | file(context, &mut symbols, &mut units, path, &Path::default(), None)?; 53 | Ok((symbols, units)) 54 | } 55 | 56 | pub fn resolve(&self, context: &Context, path: &Path, 57 | span: &Span) -> Option<(Path, &SymbolKind)> { 58 | let Path(elements) = path; 59 | let mut candidates = self.table.get(path) 60 | .map(|kind| ((path.clone(), &kind.node), kind.span.clone())) 61 | .into_iter().chain(self.includes.iter().rev() 62 | .flat_map(|includes| includes.iter().filter_map(|include| { 63 | let path = Path(match &include.node { 64 | Include::Wild(Path(other)) => other.iter() 65 | .chain(elements.iter()).cloned().collect(), 66 | Include::Item(Path(other)) => other.iter() 67 | .chain(elements.iter().skip(1)).cloned().collect(), 68 | Include::As(Path(other), identifier) if elements.len() == 1 69 | && elements.first() == Some(identifier) => other.clone(), 70 | _ => return None, 71 | }); 72 | 73 | self.table.get(&path).map(|kind| 74 | ((path, &kind.node), include.span.clone())) 75 | }))).peekable(); 76 | 77 | let (value, other) = candidates.next()?; 78 | match candidates.peek().is_some() { 79 | false => Some(value), 80 | true => { 81 | let diagnostic = Diagnostic::error() 82 | .message("ambiguous symbol resolution") 83 | .label(span.label()).label(other.other()); 84 | context.pass(candidates.fold(diagnostic, |diagnostic, (_, other)| 85 | diagnostic.label(other.other()))).ok() 86 | } 87 | } 88 | } 89 | 90 | pub fn include(&mut self, include: S) { 91 | self.includes.last_mut().expect("symbol stack is empty").push(include); 92 | } 93 | 94 | pub fn push(&mut self) { 95 | self.includes.push(Vec::new()); 96 | } 97 | 98 | pub fn pop(&mut self) { 99 | self.includes.pop().expect("symbol stack is empty"); 100 | } 101 | } 102 | 103 | fn file<'a>(context: &Context, symbols: &mut Symbols<'a>, units: &mut Vec>, 104 | file: &std::path::Path, path: &Path, span: Option) -> crate::Result<()> { 105 | let canonical = file.canonicalize().ok(); 106 | let (source, text) = { 107 | let mut files = context.files.write(); 108 | let canonical = canonical.as_ref() 109 | .and_then(|file| files.query(file)); 110 | match canonical { 111 | Some(source) => source, 112 | None => { 113 | let mut diagnostic = Diagnostic::error() 114 | .message(format!("invalid file: {}", file.display())); 115 | if let Some(span) = span { 116 | let label = span.label().with_message("referenced here"); 117 | diagnostic = diagnostic.label(label); 118 | } 119 | 120 | context.emit(diagnostic); 121 | return Ok(()); 122 | } 123 | } 124 | }; 125 | 126 | let key = Key::SymbolFile(canonical.unwrap()); 127 | context.unit.ephemeral(None, key, span.clone(), || { 128 | let file = file.parent().unwrap().to_owned(); 129 | let tree = super::parser().parse(text.as_bytes(), None).unwrap(); 130 | let source = super::Source { file: source, path: file, text }; 131 | let root_node = symbols.trees.push(tree).root_node(); 132 | traverse(context, symbols, units, &source, path, root_node) 133 | }).map(std::mem::drop) 134 | } 135 | 136 | fn traverse<'a>(context: &Context, symbols: &mut Symbols<'a>, units: &mut Vec>, 137 | source: &Source, path: &Path, node: Node<'a>) -> crate::Result<()> { 138 | let (cursor, errors) = (&mut node.walk(), &super::errors()); 139 | let mut nodes = node.named_children(cursor); 140 | nodes.try_for_each(|node: Node| Ok(match node.kind() { 141 | "ERROR" => syntax_error(context, source, node), 142 | "module" => { 143 | let element = super::field_identifier(source, node); 144 | let path = path.push(element.node.clone()); 145 | match symbols.table.get(&path) { 146 | None | Some(S { node: SymbolKind::Structure, .. }) => { 147 | units.push(Unit::Item(path.clone(), source.clone(), node)); 148 | let symbol = S::new(SymbolKind::Module, element.span); 149 | symbols.table.insert(path.clone(), symbol); 150 | traverse(context, symbols, units, source, &path, node)?; 151 | units.push(Unit::ModuleEnd); 152 | } 153 | Some(other) => context.emit(Diagnostic::error().message("duplicate symbol") 154 | .label(element.span.label()).label(other.span.label())), 155 | } 156 | } 157 | _ if !valid(context, source, errors, node) => (), 158 | "annotation" => units.push(Unit::Item(path.clone(), source.clone(), node)), 159 | "function" => function(context, symbols, units, source, 160 | path, node, super::field_identifier(source, node)), 161 | "static" => duplicate(context, symbols, units, source, path, node, 162 | SymbolKind::Variable, super::field_identifier(source, node)), 163 | "data" => duplicate(context, symbols, units, source, path, node, 164 | SymbolKind::Structure, super::field_identifier(source, node)), 165 | "use" => import(context, symbols, units, source, path, node)?, 166 | _ => (), 167 | })) 168 | } 169 | 170 | fn valid(context: &Context, source: &super::Source, 171 | errors: &Query, node: Node) -> bool { 172 | let mut error_cursor = QueryCursor::new(); 173 | let captures = error_cursor.captures(errors, node, 174 | |node| &source.text[node.byte_range()]); 175 | captures.flat_map(|(capture, _)| capture.captures) 176 | .map(|capture| syntax_error(context, source, capture.node)) 177 | .last().is_none() 178 | } 179 | 180 | fn syntax_error(context: &Context, source: &Source, node: Node) { 181 | let label = Span::new(node.byte_range(), source.file).label(); 182 | context.emit(Diagnostic::error().message("syntax error").label(label)); 183 | } 184 | 185 | fn import<'a>(context: &Context, symbols: &mut Symbols<'a>, units: &mut Vec>, 186 | source: &Source, path: &Path, node: Node<'a>) -> crate::Result<()> { 187 | let node_path = node.child_by_field_name("path").unwrap(); 188 | Ok(match node_path.kind() { 189 | "string" => { 190 | let other = super::string(source, node_path); 191 | let file = &source.path.join(other.node); 192 | let extension = file.extension() 193 | .and_then(std::ffi::OsStr::to_str); 194 | let path_as = node.child_by_field_name("as") 195 | .map(|node| super::identifier(source, node)); 196 | 197 | if extension == Some("lc") { 198 | let path = path_as.map(|node| path 199 | .push(node.node)).unwrap_or_else(|| path.clone()); 200 | self::file(context, symbols, units, file, &path, Some(other.span))?; 201 | } else if let Some(identifier) = path_as { 202 | duplicate(context, symbols, units, source, 203 | path, node, SymbolKind::Library, identifier); 204 | } 205 | } 206 | "path" => match node.child_by_field_name("as") { 207 | Some(node_as) if node_as.kind() == "signature" => 208 | node_as.child_by_field_name("identifier") 209 | .into_iter().for_each(|node_as| function(context, symbols, 210 | units, source, path, node, super::identifier(source, node_as))), 211 | Some(node_as) if node_as.kind() == "static" => 212 | duplicate(context, symbols, units, source, path, node, 213 | SymbolKind::Variable, super::field_identifier(source, node_as)), 214 | _ => units.push(Unit::Item(path.clone(), source.clone(), node)), 215 | }, 216 | _ => (), 217 | }) 218 | } 219 | 220 | fn function<'a>(context: &Context, symbols: &mut Symbols<'a>, units: &mut Vec>, 221 | source: &Source, path: &Path, node: Node<'a>, identifier: S) { 222 | let path = path.push(identifier.node); 223 | if let Some(other) = symbols.table.get(&path) { 224 | if other.node != SymbolKind::Function { 225 | context.emit(Diagnostic::error().message("duplicate symbol") 226 | .label(identifier.span.label()).label(other.span.label())); 227 | } 228 | } else { 229 | units.push(Unit::Item(path.clone(), source.clone(), node)); 230 | let symbol = S::new(SymbolKind::Function, identifier.span); 231 | symbols.table.insert(path, symbol); 232 | } 233 | } 234 | 235 | fn duplicate<'a>(context: &Context, symbols: &mut Symbols<'a>, 236 | units: &mut Vec>, source: &Source, path: &Path, 237 | node: Node<'a>, symbol: SymbolKind, identifier: S) { 238 | let path = path.push(identifier.node); 239 | match symbols.table.get(&path) { 240 | Some(other) => context.emit(Diagnostic::error().message("duplicate symbol") 241 | .label(identifier.span.label()).label(other.span.label())), 242 | None => { 243 | units.push(Unit::Item(path.clone(), source.clone(), node)); 244 | symbols.table.insert(path, S::new(symbol, identifier.span)); 245 | } 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /src/parse/value.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use tree_sitter::Node; 4 | 5 | use crate::context::Context; 6 | use crate::error::Diagnostic; 7 | use crate::node::*; 8 | use crate::span::{S, Span}; 9 | 10 | use super::{Source, SymbolKind, Symbols}; 11 | 12 | pub struct Scene<'a, 'b> { 13 | pub context: &'a Context, 14 | pub symbols: &'a Symbols<'b>, 15 | pub generations: HashMap, 16 | pub stack: Vec>, 17 | pub source: &'a Source, 18 | pub value: Value, 19 | } 20 | 21 | impl<'a, 'b> Scene<'a, 'b> { 22 | pub fn new(context: &'a Context, symbols: &'a Symbols<'b>, source: &'a Source) -> Self { 23 | let (generations, stack) = (HashMap::new(), vec![HashMap::new()]); 24 | Scene { context, symbols, generations, stack, source, value: Value::default() } 25 | } 26 | 27 | pub fn binding(&mut self, identifier: S) -> S { 28 | let generation = self.generations.entry(identifier.node.clone()).or_default(); 29 | self.stack.last_mut().unwrap().insert(identifier.node.clone(), *generation); 30 | let variable = S::new(Variable(identifier.node, *generation), identifier.span); 31 | *generation += 1; 32 | variable 33 | } 34 | 35 | fn value(&mut self, value: ValueNode, node: Node) -> ValueIndex { 36 | self.value.insert(S::create(value, node.byte_range(), self.source.file)) 37 | } 38 | 39 | fn generation(&self, identifier: &Identifier) -> Option { 40 | self.stack.iter().rev().find_map(|frame| frame.get(&identifier)).cloned() 41 | } 42 | 43 | fn variable(&mut self, identifier: S) -> crate::Result { 44 | match self.generation(&identifier.node) { 45 | Some(generation) => { 46 | let variable = ValueNode::Variable(Variable(identifier.node, generation)); 47 | Ok(self.value.insert(S::new(variable, identifier.span))) 48 | } 49 | None => self.context.pass(Diagnostic::error() 50 | .label(identifier.span.label()).message("undefined variable")) 51 | } 52 | } 53 | } 54 | 55 | pub fn value(context: &Context, symbols: &Symbols, 56 | source: &Source, node: Node) -> crate::Result { 57 | let mut scene = Scene::new(context, symbols, source); 58 | scene.value.root = unit(&mut scene, node)?; 59 | Ok(scene.value) 60 | } 61 | 62 | pub fn unit(scene: &mut Scene, node: Node) -> crate::Result { 63 | let value = match node.kind() { 64 | "break" => ValueNode::Break, 65 | "continue" => ValueNode::Continue, 66 | "path" => return path(scene, node), 67 | "group" => return unit(scene, node.named_child(0).unwrap()), 68 | "string" => ValueNode::String(super::string(scene.source, node).node), 69 | "register" => ValueNode::Register(super::register(scene.source, node).node), 70 | "truth" => ValueNode::Truth(&scene.source.text[node.byte_range()] == "true"), 71 | "rune" => super::string(scene.source, node).node 72 | .chars().next().map(ValueNode::Rune).unwrap(), 73 | "block" => { 74 | let cursor = &mut node.walk(); 75 | scene.stack.push(HashMap::new()); 76 | let block = node.named_children(cursor).map(|node| 77 | unit(scene, node)).collect::>()?; 78 | 79 | scene.stack.pop(); 80 | ValueNode::Block(block) 81 | } 82 | "integral" => { 83 | let string = &scene.source.text[node.byte_range()]; 84 | let string = &string.replace('\'', ""); 85 | ValueNode::Integral(match string.get(..2) { 86 | Some("0x") => i128::from_str_radix(&string[2..], 16), 87 | Some("0o") => i128::from_str_radix(&string[2..], 8), 88 | Some("0b") => i128::from_str_radix(&string[2..], 2), 89 | _ => i128::from_str_radix(string, 10), 90 | }.unwrap()) 91 | } 92 | "let" => { 93 | let identifier = super::field_identifier(scene.source, node); 94 | let node_type = node.child_by_field_name("type") 95 | .map(|node| super::node_type(scene.context, 96 | scene.symbols, scene.source, node)).transpose()?; 97 | let value = node.child_by_field_name("value") 98 | .map(|node| unit(scene, node)).transpose()?; 99 | ValueNode::Let(scene.binding(identifier), node_type, value) 100 | } 101 | "set" => { 102 | let target = unit(scene, node.child_by_field_name("target").unwrap())?; 103 | let value = unit(scene, node.child_by_field_name("value").unwrap())?; 104 | ValueNode::Set(target, value) 105 | } 106 | "compound" => { 107 | let target = unit(scene, node.child_by_field_name("target").unwrap())?; 108 | let value = unit(scene, node.child_by_field_name("value").unwrap())?; 109 | let operator = node.child_by_field_name("operator").unwrap(); 110 | let operator = &scene.source.text[operator.byte_range()]; 111 | let operator = Dual::parse(operator).unwrap_or_else(|| 112 | panic!("invalid compound operator: {}", operator)); 113 | ValueNode::Compound(operator, target, value) 114 | } 115 | "return" => { 116 | let value = node.child_by_field_name("value").map(|node| 117 | unit(scene, node)).transpose()?; 118 | ValueNode::Return(value) 119 | } 120 | "when" => { 121 | let cursor = &mut node.walk(); 122 | ValueNode::When(node.named_children(cursor).map(|node| 123 | Ok((unit(scene, node.child_by_field_name("condition").unwrap())?, 124 | unit(scene, node.child_by_field_name("branch").unwrap())?))) 125 | .collect::>()?) 126 | } 127 | "while" => { 128 | let condition = unit(scene, node.child_by_field_name("condition").unwrap())?; 129 | let value = unit(scene, node.child_by_field_name("block").unwrap())?; 130 | ValueNode::While(condition, value) 131 | } 132 | "access" => { 133 | let value = unit(scene, node.child_by_field_name("value").unwrap())?; 134 | let field = node.child_by_field_name("field").unwrap(); 135 | let field = super::identifier(scene.source, field); 136 | ValueNode::Field(value, field) 137 | } 138 | "create" => { 139 | let cursor = &mut node.walk(); 140 | let fields = node.children_by_field_name("field", cursor); 141 | let path = super::path(scene.source, node.child_by_field_name("path").unwrap()); 142 | let path = match scene.symbols.resolve(scene.context, &path.node, &path.span) { 143 | Some((structure, SymbolKind::Structure)) => S::new(structure, path.span), 144 | Some(_) => return scene.context.pass(Diagnostic::error().label(path.span.label()) 145 | .message(format!("symbol at path: {}, is not a data structure", path))), 146 | None => return scene.context.pass(Diagnostic::error().label(path.span.label()) 147 | .message(format!("no data structure at path: {}", path))), 148 | }; 149 | 150 | ValueNode::Create(path, fields.map(|field| Ok(match field.kind() { 151 | "identifier" => { 152 | let identifier = super::identifier(scene.source, field); 153 | let variable = scene.variable(identifier.clone())?; 154 | (identifier.node, (variable, identifier.span)) 155 | } 156 | "field" => { 157 | let name = field.child_by_field_name("name").unwrap(); 158 | let identifier = super::identifier(scene.source, name); 159 | let value = field.child_by_field_name("value").unwrap(); 160 | (identifier.node, (unit(scene, value)?, identifier.span)) 161 | } 162 | other => panic!("invalid field kind: {}", other) 163 | })).collect::>()?) 164 | } 165 | "slice" => { 166 | let value = node.child_by_field_name("value"); 167 | let value = unit(scene, value.unwrap())?; 168 | let left = node.child_by_field_name("left") 169 | .map(|node| unit(scene, node)).transpose()?; 170 | let right = node.child_by_field_name("right") 171 | .map(|node| unit(scene, node)).transpose()?; 172 | ValueNode::Slice(value, left, right) 173 | } 174 | "index" => { 175 | let value = unit(scene, node.child_by_field_name("value").unwrap())?; 176 | let index = unit(scene, node.child_by_field_name("index").unwrap())?; 177 | ValueNode::Index(value, index) 178 | } 179 | "array" => { 180 | let cursor = &mut node.walk(); 181 | let values = node.named_children(cursor).map(|node| 182 | unit(scene, node)).collect::>()?; 183 | ValueNode::Array(values) 184 | } 185 | "call" => { 186 | let path = node.child_by_field_name("function"); 187 | let path = super::path(scene.source, path.unwrap()); 188 | let span = path.span; 189 | 190 | match scene.symbols.resolve(scene.context, &path.node, &span) { 191 | Some((path, SymbolKind::Function)) | 192 | Some((path, SymbolKind::Intrinsic)) => { 193 | let cursor = &mut node.walk(); 194 | let arguments = node.children_by_field_name("argument", cursor) 195 | .map(|node| unit(scene, node)).collect::>()?; 196 | ValueNode::Call(S::new(path, span), arguments) 197 | } 198 | Some(_) => return scene.context.pass(Diagnostic::error().label(span.label()) 199 | .message(format!("symbol for path: {}, is not a function", path.node))), 200 | None => return scene.context.pass(Diagnostic::error().label(span.label()) 201 | .message(format!("no function for path: {}", path.node))) 202 | } 203 | } 204 | "cast" => { 205 | let value = unit(scene, node.child_by_field_name("value").unwrap())?; 206 | let node_type = node.child_by_field_name("type").unwrap(); 207 | let node_type = super::node_type(scene.context, 208 | scene.symbols, scene.source, node_type)?; 209 | ValueNode::Cast(value, node_type) 210 | } 211 | "unary" => { 212 | let value = unit(scene, node.child_by_field_name("value").unwrap())?; 213 | let operator = node.child_by_field_name("operator").unwrap(); 214 | match &scene.source.text[operator.byte_range()] { 215 | "#" => ValueNode::Compile(value), 216 | "inline" => ValueNode::Inline(value), 217 | "!" => ValueNode::Unary(Unary::Not, value), 218 | "-" => ValueNode::Unary(Unary::Negate, value), 219 | "&" => ValueNode::Unary(Unary::Reference, value), 220 | "*" => ValueNode::Unary(Unary::Dereference, value), 221 | other => panic!("invalid unary operator: {}", other), 222 | } 223 | } 224 | "binary" => { 225 | let left = unit(scene, node.child_by_field_name("left").unwrap())?; 226 | let right = unit(scene, node.child_by_field_name("right").unwrap())?; 227 | let operator = node.child_by_field_name("operator").unwrap(); 228 | let operator = &scene.source.text[operator.byte_range()]; 229 | let operator = Binary::parse(operator).unwrap_or_else(|| 230 | panic!("invalid binary operator: {}", operator)); 231 | ValueNode::Binary(operator, left, right) 232 | } 233 | other => panic!("invalid value kind: {}", other), 234 | }; 235 | 236 | Ok(scene.value(value, node)) 237 | } 238 | 239 | fn path(scene: &mut Scene, node: Node) -> crate::Result { 240 | let cursor = &mut node.walk(); 241 | let mut elements: Vec<_> = node.named_children(cursor).map(|node: Node| 242 | (node, super::identifier(scene.source, node))).collect(); 243 | let (first, first_element) = elements.first().unwrap(); 244 | if let Some(generation) = scene.generation(&first_element.node) { 245 | let (first, first_element) = elements.remove(0); 246 | let variable = Variable(first_element.node, generation); 247 | let variable = scene.value(ValueNode::Variable(variable), first); 248 | return Ok(path_fields(scene, variable, elements)); 249 | } 250 | 251 | let first = *first; 252 | let mut fields = Vec::new(); 253 | while !elements.is_empty() { 254 | let path = Path(elements.iter().map(|(_, element)| 255 | element.node.clone()).collect()); 256 | let (last, _) = elements.last().unwrap(); 257 | let range = first.start_byte()..last.end_byte(); 258 | let span = Span::new(range, scene.source.file); 259 | 260 | match scene.symbols.resolve(scene.context, &path, &span) { 261 | Some((path, SymbolKind::Variable)) | 262 | Some((path, SymbolKind::Module)) => { 263 | fields.reverse(); 264 | let path = S::new(ValueNode::Path(path), span); 265 | let path = scene.value.insert(path); 266 | return Ok(path_fields(scene, path, fields)); 267 | } 268 | Some(_) => return scene.context.pass(Diagnostic::error().label(span.label()) 269 | .message(format!("symbol for path: {}, is not a variable", path))), 270 | None => fields.push(elements.pop().unwrap()), 271 | }; 272 | } 273 | 274 | let path = super::path(scene.source, node); 275 | scene.context.pass(Diagnostic::error().label(path.span.label()) 276 | .message(format!("no variable for path: {}", path))) 277 | } 278 | 279 | fn path_fields(scene: &mut Scene, node: ValueIndex, 280 | fields: Vec<(Node, S)>) -> ValueIndex { 281 | fields.into_iter().rev().fold(node, |field, (node, identifier)| 282 | scene.value(ValueNode::Field(field, identifier), node)) 283 | } 284 | -------------------------------------------------------------------------------- /src/query/key.rs: -------------------------------------------------------------------------------- 1 | use crate::context::Context; 2 | use crate::error::Diagnostic; 3 | use crate::node::{FunctionPath, Path, Symbol}; 4 | use crate::query::QueryError; 5 | 6 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 7 | pub enum Key { 8 | SymbolFile(std::path::PathBuf), 9 | TypeFunction(FunctionPath), 10 | TypeVariable(Path), 11 | Offsets(Path), 12 | TraverseRoots, 13 | SymbolSize(Symbol), 14 | LoadAddress(Symbol), 15 | VirtualAddress(Symbol), 16 | Generate(FunctionPath), 17 | Analyze(FunctionPath), 18 | } 19 | 20 | impl Key { 21 | fn action(&self) -> &'static str { 22 | match self { 23 | Key::SymbolFile(_) => "in parsing symbols from file", 24 | Key::TypeFunction(_) => "in type checking function", 25 | Key::TypeVariable(_) => "in type checking static variable", 26 | Key::Offsets(_) => "in deriving structure offsets", 27 | Key::TraverseRoots => "in traversing root functions", 28 | Key::SymbolSize(_) => "in deriving symbol size", 29 | Key::LoadAddress(_) => "in deriving load address", 30 | Key::VirtualAddress(_) => "in deriving virtual address", 31 | Key::Generate(_) => "in generating function", 32 | Key::Analyze(_) => "in analyzing function", 33 | } 34 | } 35 | } 36 | 37 | pub fn emit(context: &Context, result: crate::Result) { 38 | if let Err(QueryError::Cycle(keys)) = result { 39 | let diagnostic = Diagnostic::error().message("compilation cycle"); 40 | let diagnostic = keys.into_iter().rev().filter_map(|(key, span)| 41 | span.map(|span| (key, span))).fold(diagnostic, |diagnostic, (key, span)| 42 | diagnostic.label(span.other().with_message(key.action()))); 43 | context.emit(diagnostic); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/query/mod.rs: -------------------------------------------------------------------------------- 1 | pub use key::*; 2 | pub use table::*; 3 | 4 | mod key; 5 | mod table; 6 | -------------------------------------------------------------------------------- /src/query/table.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use dashmap::DashMap; 4 | 5 | use crate::span::Span; 6 | 7 | use super::Key; 8 | 9 | #[derive(Debug)] 10 | pub enum QueryError { 11 | Cycle(Vec<(Key, Option)>), 12 | Failure, 13 | } 14 | 15 | #[derive(Debug)] 16 | pub struct Table { 17 | table: DashMap, Vec)>, 18 | } 19 | 20 | impl Table { 21 | pub fn scope(&self, parent: Option, key: Key, span: Option, 22 | function: F) -> Result, QueryError> 23 | where F: FnOnce() -> Result { 24 | if !self.table.contains_key(&key) { 25 | self.table.insert(key.clone(), (Entry::Pending, Vec::new())); 26 | self.table.insert(key.clone(), (match function() { 27 | Ok(value) => Entry::Value(Arc::new(value)), 28 | Err(QueryError::Failure) => Entry::Failure, 29 | Err(QueryError::Cycle(mut keys)) => { 30 | keys.push((key.clone(), span)); 31 | self.table.insert(key, (Entry::Failure, Vec::new())); 32 | return Err(QueryError::Cycle(keys)); 33 | } 34 | }, Vec::new())); 35 | } 36 | 37 | let mut entry = self.table.get_mut(&key).unwrap(); 38 | let (entry, dependents) = entry.value_mut(); 39 | dependents.extend(parent); 40 | match entry { 41 | Entry::Value(value) => Ok(value.clone()), 42 | Entry::Failure => Err(QueryError::Failure), 43 | Entry::Pending => Err(QueryError::Cycle(vec![(key, span)])), 44 | } 45 | } 46 | 47 | pub fn ephemeral(&self, parent: Option, key: Key, span: Option, 48 | function: F) -> Result, QueryError> 49 | where F: FnOnce() -> Result { 50 | let result = self.scope(parent, key.clone(), span, function); 51 | self.invalidate(&key); 52 | result 53 | } 54 | 55 | pub fn invalidate(&self, key: &Key) { 56 | self.table.remove(key).unwrap_or_else(|| 57 | panic!("key: {:?}, absent from query table", key)); 58 | } 59 | } 60 | 61 | impl Default for Table { 62 | fn default() -> Self { 63 | Table { table: DashMap::new() } 64 | } 65 | } 66 | 67 | #[derive(Debug)] 68 | enum Entry { 69 | Pending, 70 | Failure, 71 | Value(Arc), 72 | } 73 | -------------------------------------------------------------------------------- /src/span.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::ops::Range; 3 | 4 | use codespan::FileId; 5 | use codespan_reporting::diagnostic::Label; 6 | 7 | #[derive(Debug, Clone)] 8 | pub struct Span { 9 | span: codespan::Span, 10 | file: FileId, 11 | } 12 | 13 | impl Span { 14 | pub fn new(range: Range, file: codespan::FileId) -> Self { 15 | let range = range.start as u32..range.end as u32; 16 | Span { span: range.into(), file } 17 | } 18 | 19 | pub fn label(&self) -> Label { 20 | Label::primary(self.file, self.span) 21 | } 22 | 23 | pub fn other(&self) -> Label { 24 | Label::secondary(self.file, self.span) 25 | } 26 | } 27 | 28 | #[derive(Clone)] 29 | pub struct S { 30 | pub span: Span, 31 | pub node: T, 32 | } 33 | 34 | impl S { 35 | pub fn new(node: T, span: Span) -> Self { 36 | S { node, span } 37 | } 38 | 39 | pub fn create(node: T, range: Range, file: codespan::FileId) -> Self { 40 | S { node, span: Span::new(range, file) } 41 | } 42 | } 43 | 44 | impl AsRef for S { 45 | fn as_ref(&self) -> &T { 46 | &self.node 47 | } 48 | } 49 | 50 | impl AsMut for S { 51 | fn as_mut(&mut self) -> &mut T { 52 | &mut self.node 53 | } 54 | } 55 | 56 | impl fmt::Debug for S where T: fmt::Debug { 57 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 58 | self.node.fmt(f) 59 | } 60 | } 61 | 62 | impl fmt::Display for S where T: fmt::Display { 63 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 64 | self.node.fmt(f) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tree-sitter-lucent/README.md: -------------------------------------------------------------------------------- 1 | # tree-sitter-lucent 2 | Parser for the Lucent language. 3 | 4 | ## Development 5 | Lucent uses the `tree-sitter` library to read and parse source code. Generating the parser from the grammar specification requires the `tree-sitter-cli` tool from the `node` ecosystem. It is recommended you use the `yarn` package manager to install `tree-sitter`. 6 | 7 | ### Installation 8 | 1. `yarn` 9 | 2. Add to your shell profile if absent: `export PATH=$PATH:./node_modules/.bin` 10 | 11 | ### Generation 12 | ```tree-sitter generate``` 13 | 14 | ### Testing 15 | Run the testing corpus with: 16 | ```tree-sitter test``` 17 | 18 | A specific file can be parsed with: 19 | ```tree-sitter parse ``` 20 | -------------------------------------------------------------------------------- /tree-sitter-lucent/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "tree_sitter_lucent_binding", 5 | "include_dirs": [ 6 | " [ 20 | $._comment, 21 | /\s/, 22 | ], 23 | 24 | externals: $ => [ 25 | $._open, 26 | $._close, 27 | $._level, 28 | ], 29 | 30 | word: $ => $._identifier, 31 | 32 | rules: { 33 | source: $ => repeat(choice( 34 | field('annotation', $.global_annotation), 35 | field('item', $._item), 36 | )), 37 | 38 | _item: $ => choice( 39 | $.module, 40 | $.function, 41 | $.static, 42 | $.data, 43 | $.use, 44 | ), 45 | 46 | global_annotation: $ => seq('@@', 47 | field('name', $.identifier), 48 | field('value', $._value), 49 | ), 50 | 51 | annotation: $ => seq('@', 52 | field('name', $.identifier), 53 | field('value', $._value), 54 | ), 55 | 56 | module: $ => seq(annotations($), 'module', 57 | field('identifier', $.identifier), 58 | enclose($, field('item', $._item)), 59 | ), 60 | 61 | use: $ => seq(annotations($), 'use', 62 | choice($._use_string, $._use_identifier), '\n'), 63 | 64 | _use_string: $ => seq( 65 | field('path', $.string), 66 | optional(seq('with', field('with', $.string))), 67 | optional(seq('as', field('as', $.identifier))), 68 | ), 69 | 70 | _use_identifier: $ => seq( 71 | field('path', alias($._use_path, $.path)), 72 | optional(seq('as', field('as', choice( 73 | alias($.parameter, $.static), 74 | $.identifier, 75 | $.signature, 76 | )))), 77 | ), 78 | 79 | _use_path: $ => seq( 80 | $.identifier, repeat(seq('.', $.identifier)), 81 | optional(seq('.', choice(alias('*', $.wild), $.integral))), 82 | ), 83 | 84 | signature: $ => prec.right(seq( 85 | field('convention', optional($.identifier)), 86 | 'fn', field('identifier', $.identifier), 87 | seq('(', separated(',', field('parameter', $._type)), ')'), 88 | field('return', optional($._type)), 89 | )), 90 | 91 | data: $ => seq( 92 | 'data', field('identifier', $.identifier), 93 | enclose($, field('field', alias($.parameter, $.field))), 94 | ), 95 | 96 | 'function': $ => seq(annotations($), 97 | field('root', optional(alias('root', $.root))), 98 | field('convention', optional($.identifier)), 99 | 'fn', field('identifier', $.identifier), 100 | seq('(', separated(',', field('parameter', 101 | choice($.parameter, $.register))), ')'), 102 | field('return', optional($._root_type)), 103 | choice(field('block', $.block), 104 | seq('=', field('block', $._value))), 105 | ), 106 | 107 | parameter: $ => seq( 108 | field('identifier', $.identifier), 109 | ':', field('type', $._type) 110 | ), 111 | 112 | 'static': $ => seq(annotations($), 113 | 'static', field('identifier', $.identifier), 114 | choice( 115 | seq(':', field('type', $._type)), 116 | seq('=', field('value', $._value)), 117 | seq( 118 | ':', field('type', $._type), 119 | '=', field('value', $._value), 120 | ), 121 | ), 122 | ), 123 | 124 | block: $ => enclose($, $._statement), 125 | 126 | _root_type: $ => choice( 127 | $.register, 128 | $._type, 129 | ), 130 | 131 | _type: $ => choice( 132 | $.array_type, 133 | $.slice_type, 134 | $.pointer, 135 | $.path, 136 | ), 137 | 138 | pointer: $ => seq('*', $._type), 139 | slice_type: $ => seq('[', field('type', $._type), ';]'), 140 | array_type: $ => seq( 141 | '[', field('type', $._type), 142 | ';', field('size', $._value), ']', 143 | ), 144 | 145 | _statement: $ => choice( 146 | alias('break', $.break), 147 | alias('continue', $.continue), 148 | $._expression, 149 | $.compound, 150 | $.return, 151 | $.while, 152 | $.let, 153 | $.set, 154 | ), 155 | 156 | _expression: $ => choice( 157 | $._value, 158 | $.block, 159 | $.when, 160 | ), 161 | 162 | 'let': $ => seq( 163 | 'let', field('identifier', $.identifier), 164 | optional(seq(':', field('type', $._type))), 165 | optional(seq('=', field('value', $._expression))), 166 | ), 167 | 168 | set: $ => seq( 169 | field('target', $._value), '=', 170 | field('value', $._expression), 171 | ), 172 | 173 | compound: $ => seq( 174 | field('target', $._value), 175 | field('operator', choice( 176 | choice('+', '-', '*', '/', '%'), 177 | choice('&', '|', '^', '<<', '>>'), 178 | )), '=', field('value', $._expression), 179 | ), 180 | 181 | 'return': $ => prec.right(seq('return', 182 | field('value', optional($._expression)))), 183 | 184 | when: $ => choice( 185 | seq('when', ':', $._open, repeat1($.branch), $._close), 186 | seq('if', $.branch), 187 | ), 188 | 189 | branch: $ => seq( 190 | field('condition', $._value), 191 | ':', field('branch', $._statement), 192 | ), 193 | 194 | 'while': $ => seq('while', 195 | field('condition', $._value), 196 | ':', field('block', $._statement), 197 | ), 198 | 199 | _value: $ => prec.right(choice( 200 | $.register, 201 | $.integral, 202 | $.string, 203 | $.rune, 204 | $.truth, 205 | $.unary, 206 | $.binary, 207 | $.cast, 208 | $.call, 209 | $.array, 210 | $.index, 211 | $.slice, 212 | $.access, 213 | $.create, 214 | $.group, 215 | $.path, 216 | )), 217 | 218 | binary: $ => { 219 | const TABLE = [ 220 | [PRECEDENCE.and, '&&'], 221 | [PRECEDENCE.or, '||'], 222 | [PRECEDENCE.binary_and, '&'], 223 | [PRECEDENCE.binary_or, '|'], 224 | [PRECEDENCE.exclusive_or, '^'], 225 | [PRECEDENCE.compare, choice('==', '!=', '<', '<=', '>', '>=')], 226 | [PRECEDENCE.shift, choice('<<', '>>')], 227 | [PRECEDENCE.additive, choice('+', '-')], 228 | [PRECEDENCE.multiplicative, choice('*', '/', '%')], 229 | ]; 230 | 231 | return choice(...TABLE.map(([precedence, operator]) => 232 | prec.left(precedence, seq(field('left', $._value), 233 | field('operator', operator), field('right', $._value))))); 234 | }, 235 | 236 | unary: $ => { 237 | const TABLE = ['-', '!', '*', '&', '#', 'inline']; 238 | return prec(PRECEDENCE.unary, seq( 239 | field('operator', choice(...TABLE)), 240 | field('value', $._value), 241 | )); 242 | }, 243 | 244 | call: $ => prec(PRECEDENCE.call, seq( 245 | field('function', $.path), 246 | seq('(', separated(',', 247 | field('argument', $._value) 248 | ), ')') 249 | )), 250 | 251 | cast: $ => seq( 252 | field('value', $._value), 253 | 'as', field('type', $._type), 254 | ), 255 | 256 | index: $ => prec(PRECEDENCE.call, seq( 257 | field('value', $._value), 258 | '[', field('index', $._value), ']', 259 | )), 260 | 261 | slice: $ => prec(PRECEDENCE.call, seq( 262 | field('value', $._value), 263 | '[', field('left', optional($._value)), 264 | ':', field('right', optional($._value)), ']', 265 | )), 266 | 267 | access: $ => prec(PRECEDENCE.access, seq( 268 | field('value', $._value), '.', 269 | field('field', $.identifier), 270 | )), 271 | 272 | create: $ => prec.right(seq( 273 | field('path', $.path), '~', 274 | separated(',', prec.right(field('field', 275 | choice($.identifier, $.field)))), 276 | )), 277 | 278 | field: $ => prec.right(seq( 279 | field('name', $.identifier), '=', 280 | field('value', $._value), 281 | )), 282 | 283 | group: $ => seq('(', $._value, ')'), 284 | array: $ => seq('[', separated(',', $._value), ']'), 285 | path: $ => prec.right(seq($.identifier, 286 | repeat(seq('.', $.identifier)))), 287 | 288 | integral: $ => choice( 289 | /0b[0-1]([0-1']*[0-1])?/, 290 | /0o[0-7]([0-7']*[0-7])?/, 291 | /0x[\da-f]([\da-f']*[\da-f])?/, 292 | /\d([\d']*\d)?/, 293 | ), 294 | 295 | truth: $ => choice('true', 'false'), 296 | register: $ => seq('$', $._identifier), 297 | string: $ => /"(\\.|[^"])*"/, 298 | rune: $ => /'(\\.|[^"])'/, 299 | 300 | identifier: $ => $._identifier, 301 | _identifier: $ => /[^\x00-@\[-^`{-~][^\x00-&(-/:-@\[-^`{-~]*/, 302 | _comment: $ => token(seq('//', /[^\n]*/)), 303 | } 304 | }); 305 | 306 | function annotations($) { 307 | return field('annotation', repeat($.annotation)); 308 | } 309 | 310 | function enclose($, rule) { 311 | return seq($._open, rule, repeat(seq($._level, rule)), $._close); 312 | } 313 | 314 | function separated1(separator, rule) { 315 | return seq(rule, repeat(seq(separator, rule)), optional(separator)); 316 | } 317 | 318 | function separated(separator, rule) { 319 | return optional(separated1(separator, rule)); 320 | } 321 | -------------------------------------------------------------------------------- /tree-sitter-lucent/index.js: -------------------------------------------------------------------------------- 1 | try { 2 | module.exports = require("./build/Release/tree_sitter_lucent_binding"); 3 | } catch (error) { 4 | try { 5 | module.exports = require("./build/Debug/tree_sitter_lucent_binding"); 6 | } catch (_) { 7 | throw error 8 | } 9 | } 10 | 11 | try { 12 | module.exports.nodeTypeInfo = require("./src/node-types.json"); 13 | } catch (_) {} 14 | -------------------------------------------------------------------------------- /tree-sitter-lucent/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-lucent", 3 | "version": "0.1.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "nan": "^2.14.1" 8 | }, 9 | "devDependencies": { 10 | "tree-sitter-cli": "^0.16.7" 11 | }, 12 | "tree-sitter": [ 13 | { 14 | "scope": "source.lc", 15 | "file-types": [ 16 | "lc" 17 | ] 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /tree-sitter-lucent/queries/highlights.scm: -------------------------------------------------------------------------------- 1 | "module" @keyword 2 | "when" @keyword 3 | "fn" @keyword 4 | "data" @keyword 5 | "static" @keyword 6 | "inline" @keyword 7 | "return" @keyword 8 | "while" @keyword 9 | "with" @keyword 10 | "use" @keyword 11 | "as" @keyword 12 | 13 | "!" @operator 14 | "#" @operator 15 | "&&" @operator 16 | "||" @operator 17 | "&" @operator 18 | "|" @operator 19 | "^" @operator 20 | "==" @operator 21 | "!=" @operator 22 | "<" @operator 23 | "<=" @operator 24 | ">" @operator 25 | ">=" @operator 26 | "<<" @operator 27 | ">>" @operator 28 | "+" @operator 29 | "-" @operator 30 | "*" @operator 31 | "/" @operator 32 | "%" @operator 33 | 34 | ("+" "=") @operator 35 | ("-" "=") @operator 36 | ("*" "=") @operator 37 | ("/" "=") @operator 38 | ("%" "=") @operator 39 | ("&" "=") @operator 40 | ("|" "=") @operator 41 | ("^" "=") @operator 42 | ("<<" "=") @operator 43 | (">>" "=") @operator 44 | 45 | "." @delimiter 46 | "," @delimiter 47 | ":" @delimiter 48 | ";" @delimiter 49 | "(" @bracket 50 | ")" @bracket 51 | 52 | (string) @string 53 | (integral) @number 54 | (register) @number 55 | (rune) @number 56 | "true" @number 57 | "false" @number 58 | 59 | (annotation "@" @property 60 | name: (identifier) @property) 61 | 62 | (global_annotation "@@" @property 63 | name: (identifier) @property) 64 | 65 | (root) @keyword 66 | (break) @keyword 67 | (identifier) @variable 68 | -------------------------------------------------------------------------------- /tree-sitter-lucent/src/binding.cc: -------------------------------------------------------------------------------- 1 | #include "tree_sitter/parser.h" 2 | #include 3 | #include "nan.h" 4 | 5 | using namespace v8; 6 | 7 | extern "C" TSLanguage * tree_sitter_lucent(); 8 | 9 | namespace { 10 | 11 | NAN_METHOD(New) {} 12 | 13 | void Init(Local exports, Local module) { 14 | Local tpl = Nan::New(New); 15 | tpl->SetClassName(Nan::New("Language").ToLocalChecked()); 16 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 17 | 18 | Local constructor = Nan::GetFunction(tpl).ToLocalChecked(); 19 | Local instance = constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked(); 20 | Nan::SetInternalFieldPointer(instance, 0, tree_sitter_lucent()); 21 | 22 | Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("lucent").ToLocalChecked()); 23 | Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance); 24 | } 25 | 26 | NODE_MODULE(tree_sitter_lucent_binding, Init) 27 | 28 | } // namespace 29 | -------------------------------------------------------------------------------- /tree-sitter-lucent/src/scanner.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define CONCATENATE(a, b) a ## _ ## b 5 | #define EVALUATE(a, b) CONCATENATE(a, b) 6 | #define PREFIX tree_sitter_lucent_external_scanner 7 | #define FUNCTION(identifier) EVALUATE(PREFIX, identifier) 8 | 9 | enum Token { 10 | OPEN, 11 | CLOSE, 12 | LEVEL, 13 | }; 14 | 15 | struct Scanner { 16 | uint16_t current; 17 | uint16_t target; 18 | }; 19 | 20 | void* FUNCTION(create)() { 21 | struct Scanner* scanner = malloc(sizeof(struct Scanner)); 22 | scanner->current = 0; 23 | scanner->target = 0; 24 | return scanner; 25 | } 26 | 27 | void FUNCTION(destroy)(void* object) { 28 | free((struct Scanner*) object); 29 | } 30 | 31 | unsigned FUNCTION(serialize)(void* object, char* buffer) { 32 | size_t size = sizeof(struct Scanner); 33 | memcpy(buffer, object, size); 34 | return size; 35 | } 36 | 37 | void FUNCTION(deserialize)(void* object, const char* buffer, unsigned length) { 38 | memcpy(object, buffer, length); 39 | } 40 | 41 | bool step(struct Scanner* scanner, TSLexer* lexer, const bool* valid) { 42 | if (valid[OPEN] && scanner->current < scanner->target) { 43 | lexer->result_symbol = OPEN; 44 | ++scanner->current; 45 | return true; 46 | } 47 | 48 | if (valid[CLOSE] && scanner->current > scanner->target) { 49 | lexer->result_symbol = CLOSE; 50 | --scanner->current; 51 | return true; 52 | } 53 | 54 | return false; 55 | } 56 | 57 | bool FUNCTION(scan)(void* object, TSLexer* lexer, const bool* valid) { 58 | struct Scanner* scanner = object; 59 | if (step(scanner, lexer, valid)) 60 | return true; 61 | 62 | lexer->mark_end(lexer); 63 | if (valid[OPEN] || valid[CLOSE] || valid[LEVEL]) { 64 | bool new_line = lexer->get_column(lexer) == 0; 65 | uint16_t length = 0; 66 | while (true) { 67 | if (lexer->lookahead == '\0') { 68 | length = 0; 69 | break; 70 | } else if (lexer->lookahead == '\n') { 71 | lexer->advance(lexer, true); 72 | new_line = true; 73 | length = 0; 74 | } else if (lexer->lookahead == '\t') { 75 | lexer->advance(lexer, true), ++length; 76 | } else if (lexer->lookahead == ' ') { 77 | lexer->advance(lexer, true); 78 | } else if (!new_line) { 79 | return false; 80 | } else break; 81 | } 82 | 83 | if (valid[LEVEL] && scanner->current == length) { 84 | lexer->result_symbol = LEVEL; 85 | return true; 86 | } 87 | 88 | scanner->target = length; 89 | return step(scanner, lexer, valid); 90 | } 91 | 92 | return false; 93 | } 94 | -------------------------------------------------------------------------------- /tree-sitter-lucent/src/tree_sitter/parser.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_PARSER_H_ 2 | #define TREE_SITTER_PARSER_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #define ts_builtin_sym_error ((TSSymbol)-1) 13 | #define ts_builtin_sym_end 0 14 | #define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024 15 | 16 | #ifndef TREE_SITTER_API_H_ 17 | typedef uint16_t TSSymbol; 18 | typedef uint16_t TSFieldId; 19 | typedef struct TSLanguage TSLanguage; 20 | #endif 21 | 22 | typedef struct { 23 | TSFieldId field_id; 24 | uint8_t child_index; 25 | bool inherited; 26 | } TSFieldMapEntry; 27 | 28 | typedef struct { 29 | uint16_t index; 30 | uint16_t length; 31 | } TSFieldMapSlice; 32 | 33 | typedef uint16_t TSStateId; 34 | 35 | typedef struct { 36 | bool visible : 1; 37 | bool named : 1; 38 | } TSSymbolMetadata; 39 | 40 | typedef struct TSLexer TSLexer; 41 | 42 | struct TSLexer { 43 | int32_t lookahead; 44 | TSSymbol result_symbol; 45 | void (*advance)(TSLexer *, bool); 46 | void (*mark_end)(TSLexer *); 47 | uint32_t (*get_column)(TSLexer *); 48 | bool (*is_at_included_range_start)(const TSLexer *); 49 | bool (*eof)(const TSLexer *); 50 | }; 51 | 52 | typedef enum { 53 | TSParseActionTypeShift, 54 | TSParseActionTypeReduce, 55 | TSParseActionTypeAccept, 56 | TSParseActionTypeRecover, 57 | } TSParseActionType; 58 | 59 | typedef struct { 60 | union { 61 | struct { 62 | TSStateId state; 63 | bool extra : 1; 64 | bool repetition : 1; 65 | } shift; 66 | struct { 67 | TSSymbol symbol; 68 | int16_t dynamic_precedence; 69 | uint8_t child_count; 70 | uint8_t production_id; 71 | } reduce; 72 | } params; 73 | TSParseActionType type : 4; 74 | } TSParseAction; 75 | 76 | typedef struct { 77 | uint16_t lex_state; 78 | uint16_t external_lex_state; 79 | } TSLexMode; 80 | 81 | typedef union { 82 | TSParseAction action; 83 | struct { 84 | uint8_t count; 85 | bool reusable : 1; 86 | } entry; 87 | } TSParseActionEntry; 88 | 89 | struct TSLanguage { 90 | uint32_t version; 91 | uint32_t symbol_count; 92 | uint32_t alias_count; 93 | uint32_t token_count; 94 | uint32_t external_token_count; 95 | const char **symbol_names; 96 | const TSSymbolMetadata *symbol_metadata; 97 | const uint16_t *parse_table; 98 | const TSParseActionEntry *parse_actions; 99 | const TSLexMode *lex_modes; 100 | const TSSymbol *alias_sequences; 101 | uint16_t max_alias_sequence_length; 102 | bool (*lex_fn)(TSLexer *, TSStateId); 103 | bool (*keyword_lex_fn)(TSLexer *, TSStateId); 104 | TSSymbol keyword_capture_token; 105 | struct { 106 | const bool *states; 107 | const TSSymbol *symbol_map; 108 | void *(*create)(void); 109 | void (*destroy)(void *); 110 | bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist); 111 | unsigned (*serialize)(void *, char *); 112 | void (*deserialize)(void *, const char *, unsigned); 113 | } external_scanner; 114 | uint32_t field_count; 115 | const TSFieldMapSlice *field_map_slices; 116 | const TSFieldMapEntry *field_map_entries; 117 | const char **field_names; 118 | uint32_t large_state_count; 119 | const uint16_t *small_parse_table; 120 | const uint32_t *small_parse_table_map; 121 | const TSSymbol *public_symbol_map; 122 | }; 123 | 124 | /* 125 | * Lexer Macros 126 | */ 127 | 128 | #define START_LEXER() \ 129 | bool result = false; \ 130 | bool skip = false; \ 131 | bool eof = false; \ 132 | int32_t lookahead; \ 133 | goto start; \ 134 | next_state: \ 135 | lexer->advance(lexer, skip); \ 136 | start: \ 137 | skip = false; \ 138 | lookahead = lexer->lookahead; 139 | 140 | #define ADVANCE(state_value) \ 141 | { \ 142 | state = state_value; \ 143 | goto next_state; \ 144 | } 145 | 146 | #define SKIP(state_value) \ 147 | { \ 148 | skip = true; \ 149 | state = state_value; \ 150 | goto next_state; \ 151 | } 152 | 153 | #define ACCEPT_TOKEN(symbol_value) \ 154 | result = true; \ 155 | lexer->result_symbol = symbol_value; \ 156 | lexer->mark_end(lexer); 157 | 158 | #define END_STATE() return result; 159 | 160 | /* 161 | * Parse Table Macros 162 | */ 163 | 164 | #define SMALL_STATE(id) id - LARGE_STATE_COUNT 165 | 166 | #define STATE(id) id 167 | 168 | #define ACTIONS(id) id 169 | 170 | #define SHIFT(state_value) \ 171 | { \ 172 | { \ 173 | .params = { \ 174 | .shift = { \ 175 | .state = state_value \ 176 | } \ 177 | }, \ 178 | .type = TSParseActionTypeShift \ 179 | } \ 180 | } 181 | 182 | #define SHIFT_REPEAT(state_value) \ 183 | { \ 184 | { \ 185 | .params = { \ 186 | .shift = { \ 187 | .state = state_value, \ 188 | .repetition = true \ 189 | } \ 190 | }, \ 191 | .type = TSParseActionTypeShift \ 192 | } \ 193 | } 194 | 195 | #define RECOVER() \ 196 | { \ 197 | { .type = TSParseActionTypeRecover } \ 198 | } 199 | 200 | #define SHIFT_EXTRA() \ 201 | { \ 202 | { \ 203 | .params = { \ 204 | .shift = { \ 205 | .extra = true \ 206 | } \ 207 | }, \ 208 | .type = TSParseActionTypeShift \ 209 | } \ 210 | } 211 | 212 | #define REDUCE(symbol_val, child_count_val, ...) \ 213 | { \ 214 | { \ 215 | .params = { \ 216 | .reduce = { \ 217 | .symbol = symbol_val, \ 218 | .child_count = child_count_val, \ 219 | __VA_ARGS__ \ 220 | }, \ 221 | }, \ 222 | .type = TSParseActionTypeReduce \ 223 | } \ 224 | } 225 | 226 | #define ACCEPT_INPUT() \ 227 | { \ 228 | { .type = TSParseActionTypeAccept } \ 229 | } 230 | 231 | #ifdef __cplusplus 232 | } 233 | #endif 234 | 235 | #endif // TREE_SITTER_PARSER_H_ 236 | -------------------------------------------------------------------------------- /tree-sitter-lucent/test/corpus/expressions.txt: -------------------------------------------------------------------------------- 1 | ===================================== 2 | Literals 3 | ===================================== 4 | 5 | fn function() 6 | 0 7 | 0x0 8 | 0xabc'def 9 | 0o01234567 10 | "string" 11 | "\"string\"" 12 | $register 13 | true 14 | 'a' 15 | 16 | --- 17 | 18 | (source (function 19 | (identifier) (block 20 | (integral) (integral) (integral) (integral) 21 | (string) (string) (register) (truth) (rune)))) 22 | 23 | ===================================== 24 | Let statements 25 | ===================================== 26 | 27 | fn function() 28 | let identifier: type = value 29 | let identifier = value 30 | let identifier: type 31 | let identifier 32 | 33 | --- 34 | 35 | (source item: (function 36 | identifier: (identifier) 37 | block: (block 38 | (let identifier: (identifier) 39 | type: (path (identifier)) 40 | value: (path (identifier))) 41 | (let identifier: (identifier) 42 | value: (path (identifier))) 43 | (let identifier: (identifier) 44 | type: (path (identifier))) 45 | (let identifier: (identifier))))) 46 | 47 | ===================================== 48 | Binary expressions 49 | ===================================== 50 | 51 | fn function() 52 | 1 + 1 53 | 1 - 1 * 1 54 | 1 + (1 - 1) 55 | 1 + 1 / 1 % 1 56 | 57 | --- 58 | 59 | (source (function 60 | (identifier) (block 61 | (binary (integral) (integral)) 62 | (binary (integral) (binary (integral) (integral))) 63 | (binary (integral) (group (binary (integral) (integral)))) 64 | (binary (integral) (binary (binary 65 | (integral) (integral)) (integral)))))) 66 | 67 | ===================================== 68 | Unary expressions 69 | ===================================== 70 | 71 | fn function() 72 | -1 + *&identifier 73 | !true 74 | 75 | --- 76 | 77 | (source (function 78 | (identifier) (block 79 | (binary (unary (integral)) 80 | (unary (unary (path (identifier))))) 81 | (unary (truth))))) 82 | 83 | ===================================== 84 | Cast expressions 85 | ===================================== 86 | 87 | fn function() 88 | 1 as truth 89 | 1 as i32 as truth 90 | 91 | --- 92 | 93 | (source (function 94 | (identifier) (block 95 | (cast (integral) (path (identifier))) 96 | (cast (cast (integral) (path (identifier))) 97 | (path (identifier)))))) 98 | 99 | ===================================== 100 | Function calls 101 | ===================================== 102 | 103 | fn function() 104 | function() 105 | let value = function() 106 | function(1, true, function()) 107 | 108 | --- 109 | 110 | (source item: (function 111 | identifier: (identifier) block: (block 112 | (call function: (path (identifier))) 113 | (let identifier: (identifier) 114 | value: (call function: (path (identifier)))) 115 | (call function: (path (identifier)) 116 | argument: (integral) argument: (truth) 117 | argument: (call function: (path (identifier))))))) 118 | 119 | ===================================== 120 | Function returns 121 | ===================================== 122 | 123 | fn function() 124 | return identifier 125 | return 126 | 127 | --- 128 | 129 | (source (function 130 | (identifier) (block 131 | (return (path (identifier))) 132 | (return)))) 133 | 134 | ===================================== 135 | Arrays 136 | ===================================== 137 | 138 | fn function() 139 | let variable: [u8; 3] = [1, 2, 3] 140 | variable[0] 141 | 142 | --- 143 | 144 | (source (function 145 | (identifier) (block 146 | (let (identifier) 147 | (array_type (path (identifier)) (integral)) 148 | (array (integral) (integral) (integral))) 149 | (index (path (identifier)) (integral))))) 150 | 151 | ===================================== 152 | Slices 153 | ===================================== 154 | 155 | fn function() 156 | let variable: [u8;] = [][0:0] 157 | variable[:] 158 | 159 | --- 160 | 161 | (source (function 162 | (identifier) (block 163 | (let (identifier) 164 | (slice_type (path (identifier))) 165 | (slice (array) (integral) (integral))) 166 | (slice (path (identifier)))))) 167 | 168 | ===================================== 169 | Pointers 170 | ===================================== 171 | 172 | fn function() 173 | let variable: **u8 = 0 as *u8 as **u8 174 | **variable 175 | 176 | --- 177 | 178 | (source (function 179 | (identifier) (block 180 | (let (identifier) 181 | (pointer (pointer (path (identifier)))) 182 | (cast (cast (integral) 183 | (pointer (path (identifier)))) 184 | (pointer (pointer (path (identifier)))))) 185 | (unary (unary (path (identifier))))))) 186 | 187 | ===================================== 188 | If expressions 189 | ===================================== 190 | 191 | fn function() 192 | if true: true 193 | if true: 194 | true 195 | true 196 | 197 | --- 198 | 199 | (source (function 200 | (identifier) (block 201 | (when (branch (truth) (truth))) 202 | (when (branch (truth) 203 | (block (truth) (truth))))))) 204 | 205 | ===================================== 206 | When expressions 207 | ===================================== 208 | 209 | fn function() 210 | let variable = when: 211 | false: 0 212 | true: 1 213 | 214 | --- 215 | 216 | (source (function 217 | (identifier) (block 218 | (let (identifier) (when 219 | (branch (truth) (integral)) 220 | (branch (truth) (integral))))))) 221 | 222 | ===================================== 223 | While loops 224 | ===================================== 225 | 226 | fn function() 227 | while true: true 228 | while true: continue 229 | while true: 230 | break 231 | return 232 | 233 | --- 234 | 235 | (source (function 236 | (identifier) (block 237 | (while (truth) (truth)) 238 | (while (truth) (continue)) 239 | (while (truth) (block (break) (return)))))) 240 | 241 | ===================================== 242 | Construction 243 | ===================================== 244 | 245 | fn function() 246 | Structure ~ field = true, field 247 | 248 | --- 249 | 250 | (source (function 251 | (identifier) (block 252 | (create (path (identifier)) 253 | (field (identifier) (truth)) 254 | (identifier))))) 255 | 256 | ===================================== 257 | Fields 258 | ===================================== 259 | 260 | fn function() 261 | identifier.field 262 | (identifier).field 263 | (identifier).field.field 264 | 265 | --- 266 | 267 | (source (function 268 | (identifier) (block 269 | (path (identifier) (identifier)) 270 | (access (group (path (identifier))) (identifier)) 271 | (access (access (group (path (identifier))) 272 | (identifier)) (identifier))))) 273 | 274 | ===================================== 275 | Assignment 276 | ===================================== 277 | 278 | fn function() 279 | identifier = true 280 | *identifier() = 281 | true 282 | 283 | --- 284 | 285 | (source (function 286 | (identifier) (block 287 | (set (path (identifier)) (truth)) 288 | (set (unary (call (path (identifier)))) 289 | (block (truth)))))) 290 | 291 | ===================================== 292 | Compound assignment 293 | ===================================== 294 | 295 | fn function() 296 | identifier += 0 297 | identifier -= 0 298 | identifier %= 0 299 | identifier &= 0 300 | identifier ^= 0 301 | 302 | --- 303 | 304 | (source (function 305 | (identifier) (block 306 | (compound (path (identifier)) (integral)) 307 | (compound (path (identifier)) (integral)) 308 | (compound (path (identifier)) (integral)) 309 | (compound (path (identifier)) (integral)) 310 | (compound (path (identifier)) (integral))))) 311 | -------------------------------------------------------------------------------- /tree-sitter-lucent/test/corpus/items.txt: -------------------------------------------------------------------------------- 1 | ===================================== 2 | Comments 3 | ===================================== 4 | 5 | fn function() // truth 6 | // true 7 | true 8 | 9 | --- 10 | 11 | (source (function (identifier) 12 | (block (truth)))) 13 | 14 | ===================================== 15 | Functions 16 | ===================================== 17 | 18 | fn function(first: type, second: type) truth 19 | true 20 | 21 | --- 22 | 23 | (source 24 | item: (function 25 | identifier: (identifier) 26 | parameter: (parameter 27 | identifier: (identifier) 28 | type: (path (identifier))) 29 | parameter: (parameter 30 | identifier: (identifier) 31 | type: (path (identifier))) 32 | return: (path (identifier)) 33 | block: (block (truth)))) 34 | 35 | ===================================== 36 | Void functions 37 | ===================================== 38 | 39 | fn function(parameter: type) 40 | true 41 | 42 | --- 43 | 44 | (source 45 | item: (function 46 | identifier: (identifier) 47 | parameter: (parameter 48 | identifier: (identifier) 49 | type: (path (identifier))) 50 | block: (block (truth)))) 51 | 52 | ===================================== 53 | Expression functions 54 | ===================================== 55 | 56 | fn function() truth = true 57 | 58 | --- 59 | 60 | (source 61 | item: (function 62 | identifier: (identifier) 63 | return: (path (identifier)) 64 | block: (truth))) 65 | 66 | ===================================== 67 | Calling conventions 68 | ===================================== 69 | 70 | cdecl fn function() truth = true 71 | 72 | --- 73 | 74 | (source 75 | item: (function 76 | convention: (identifier) 77 | identifier: (identifier) 78 | return: (path (identifier)) 79 | block: (truth))) 80 | 81 | ===================================== 82 | Root functions 83 | ===================================== 84 | 85 | root fn function() truth = true 86 | 87 | --- 88 | 89 | (source 90 | item: (function 91 | root: (root) 92 | identifier: (identifier) 93 | return: (path (identifier)) 94 | block: (truth))) 95 | 96 | ===================================== 97 | Static variables 98 | ===================================== 99 | 100 | static identifier: truth = true 101 | static identifier: truth 102 | static identifier = true 103 | 104 | --- 105 | 106 | (source 107 | item: (static 108 | identifier: (identifier) 109 | type: (path (identifier)) 110 | value: (truth)) 111 | item: (static 112 | identifier: (identifier) 113 | type: (path (identifier))) 114 | item: (static 115 | identifier: (identifier) 116 | value: (truth))) 117 | 118 | ===================================== 119 | Modules 120 | ===================================== 121 | 122 | module Module 123 | module Module 124 | fn function() 125 | true 126 | 127 | static variable: truth 128 | 129 | --- 130 | 131 | (source 132 | (module (identifier) 133 | (module (identifier) 134 | (function (identifier) (block (truth)))) 135 | (static (identifier) (path (identifier))))) 136 | 137 | ===================================== 138 | Structures 139 | ===================================== 140 | 141 | data Structure 142 | field: truth 143 | other: truth 144 | 145 | --- 146 | 147 | (source (data (identifier) 148 | (field (identifier) (path (identifier))) 149 | (field (identifier) (path (identifier))))) 150 | 151 | ===================================== 152 | Annotations 153 | ===================================== 154 | 155 | @annotation parameter 156 | module Module 157 | static variable: truth 158 | 159 | @@annotation parameter 160 | 161 | --- 162 | 163 | (source 164 | (module (annotation (identifier) (path (identifier))) 165 | (identifier) (static (identifier) (path (identifier)))) 166 | (global_annotation (identifier) (path (identifier)))) 167 | 168 | ===================================== 169 | Imports 170 | ===================================== 171 | 172 | use "path" 173 | use "path" with "path" 174 | use "path" as identifier 175 | use identifier.function as fn function(type) type 176 | use identifier.0x0000 as convention fn function() 177 | use identifier.symbol as variable: type 178 | use identifier.* 179 | use identifier 180 | 181 | --- 182 | 183 | (source 184 | (use (string)) 185 | (use (string) (string)) 186 | (use (string) (identifier)) 187 | (use (path (identifier) (identifier)) 188 | (signature (identifier) (path (identifier)) 189 | (path (identifier)))) 190 | (use (path (identifier) (integral)) 191 | (signature (identifier) (identifier))) 192 | (use (path (identifier) (identifier)) 193 | (static (identifier) (path (identifier)))) 194 | (use (path (identifier) (wild))) 195 | (use (path (identifier)))) 196 | -------------------------------------------------------------------------------- /tree-sitter-lucent/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | nan@^2.14.1: 6 | version "2.14.1" 7 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" 8 | integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== 9 | 10 | tree-sitter-cli@^0.16.7: 11 | version "0.16.7" 12 | resolved "https://registry.yarnpkg.com/tree-sitter-cli/-/tree-sitter-cli-0.16.7.tgz#6448eab395214a4bead13b16f89751bdad87c8ee" 13 | integrity sha512-nupMLwveMlOCni7VoenQb02h0tBZvX1wpXW5r5hRKpliOQO/Mvau+X1Ug1hvYlnCGgqPQqYFIOoumT87nJBkhA== 14 | --------------------------------------------------------------------------------