sterling os, moved sterling lang into same project directory
This commit is contained in:
commit
f2ffe70790
54
.gitignore
vendored
Normal file
54
.gitignore
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
*_exclude
|
||||
19
LICENSE
Normal file
19
LICENSE
Normal file
@ -0,0 +1,19 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
Copyright 2025 Carle-Margueritte Alexandre
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
10
LICENSE_OVERVIEW.md
Normal file
10
LICENSE_OVERVIEW.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Sterling OS License Overview
|
||||
|
||||
This repository contains multiple components under different licenses:
|
||||
|
||||
- **Sterling Programming Language (compiler/runtime/stdlib)** — Apache-2.0
|
||||
- **Sterling OS (kernel, bootloader, userland)** — 0BSD
|
||||
- **All documentation and HTML content** — MIT
|
||||
|
||||
We prioritize maximum freedom, composability, and reuse across all domains.
|
||||
|
||||
12
boot/LICENSE
Normal file
12
boot/LICENSE
Normal file
@ -0,0 +1,12 @@
|
||||
0BSD License
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
12
docs/LICENSE
Normal file
12
docs/LICENSE
Normal file
@ -0,0 +1,12 @@
|
||||
MIT License
|
||||
|
||||
Copyright 2025 Carle-Margueritte Alexandre
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this documentation to deal in the Documentation without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Documentation, and to
|
||||
permit persons to whom the Documentation is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
THE DOCUMENTATION IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
|
||||
163
docs/design.html
Normal file
163
docs/design.html
Normal file
@ -0,0 +1,163 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Operating System Design Manifesto</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: monospace;
|
||||
background-color: #fefefe;
|
||||
color: #111;
|
||||
max-width: 960px;
|
||||
margin: auto;
|
||||
padding: 2rem;
|
||||
}
|
||||
h1, h2, h3 {
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding-bottom: 0.2em;
|
||||
margin-top: 2em;
|
||||
}
|
||||
pre {
|
||||
background: #eee;
|
||||
padding: 1em;
|
||||
overflow: auto;
|
||||
}
|
||||
code {
|
||||
background: #eee;
|
||||
padding: 0.1em 0.3em;
|
||||
}
|
||||
ul {
|
||||
padding-left: 1.5em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Minimal Capability-Based Operating System</h1>
|
||||
|
||||
<h2>Design Principles</h2>
|
||||
<ul>
|
||||
<li>No global filesystem, no path resolution</li>
|
||||
<li>No drivers in kernel, only sandboxed userspace driver processes</li>
|
||||
<li>No GPU acceleration, all rendering is deterministic software-based</li>
|
||||
<li>All resources accessed via capability tokens</li>
|
||||
<li>Processes are strictly sandboxed</li>
|
||||
<li>Programs operate on memory buffers, not raw file handles</li>
|
||||
<li>Desktop environment is a sandboxed coordinator, not a privileged process</li>
|
||||
</ul>
|
||||
|
||||
<h2>Authorization Token Model</h2>
|
||||
<p>Programs delegate access via opaque, kernel-managed tokens.</p>
|
||||
<pre><code>grant_token(target_pid, resource_id, flags) -> token_id
|
||||
accept_token(token_id) -> resource_handle
|
||||
revoke_token(token_id)</code></pre>
|
||||
|
||||
<h2>File Editing Flow</h2>
|
||||
<ol>
|
||||
<li>DE requests file via storage service</li>
|
||||
<li>Storage service provides a memory buffer</li>
|
||||
<li>Editor process receives buffer handle, edits</li>
|
||||
<li>Changes submitted back to storage via DE</li>
|
||||
</ol>
|
||||
|
||||
<h2>Driver Model</h2>
|
||||
<ul>
|
||||
<li>All drivers run as fully unprivileged user processes</li>
|
||||
<li>No driver registration or kernel mediation required</li>
|
||||
<li>Drivers communicate with hardware via explicit kernel-exposed capability channels</li>
|
||||
<li>No dynamic linking or privileged probing allowed</li>
|
||||
<li>Users can run or replace any driver without OS permission</li>
|
||||
</ul>
|
||||
|
||||
<h2>Graphics System</h2>
|
||||
<ul>
|
||||
<li>No GPU support, no shaders</li>
|
||||
<li>Software renderer processes draw via shared memory</li>
|
||||
<li>DE composites framebuffers deterministically</li>
|
||||
</ul>
|
||||
|
||||
<h2>Programming Language Requirements</h2>
|
||||
<ul>
|
||||
<li>Manual memory management</li>
|
||||
<li>Low-level data layout control</li>
|
||||
<li>Inline assembly support</li>
|
||||
<li>Pattern matching and compile-time macros</li>
|
||||
<li>No runtime, no global init, no dynamic linking</li>
|
||||
</ul>
|
||||
|
||||
<h2>Execution Model</h2>
|
||||
<ul>
|
||||
<li>Programs are spawned with exact buffer and token permissions</li>
|
||||
<li>No shared global state</li>
|
||||
<li>All IO is mediated via explicit capability-based services</li>
|
||||
<li>Everything is inspectable and reproducible</li>
|
||||
</ul>
|
||||
|
||||
<h2>Sandboxing Model</h2>
|
||||
<p>All processes are isolated via strict memory boundaries and capability-scoped access. No process can access global state, shared memory, or system calls without explicit capability grants.</p>
|
||||
|
||||
<h3>Memory Layout</h3>
|
||||
<pre class="diagram">
|
||||
+-----------------------+
|
||||
| Code (RX) |
|
||||
+-----------------------+
|
||||
| Data (RW) |
|
||||
+-----------------------+
|
||||
| Shared Buffers (RWX?) | ← only if explicitly mapped by kernel
|
||||
+-----------------------+
|
||||
| Stack (RW) |
|
||||
+-----------------------+
|
||||
</pre>
|
||||
|
||||
<h3>Process Launch</h3>
|
||||
<ul>
|
||||
<li>Preallocated memory map (no heap growth)</li>
|
||||
<li>Passed a syscall pointer table, token list, and init buffer</li>
|
||||
<li>Cannot request global system resources directly</li>
|
||||
</ul>
|
||||
|
||||
<h3>Capability Enforcement</h3>
|
||||
<p>All access is mediated via capability tokens, handed off securely:</p>
|
||||
<pre><code>
|
||||
token_id = request_token(pid, SERVICE_IO, READ_WRITE);
|
||||
handle = accept_token(token_id);
|
||||
</code></pre>
|
||||
<ul>
|
||||
<li>Token scope, rights, and duration enforced by kernel</li>
|
||||
<li>No access without explicit grant</li>
|
||||
<li>All capability use is auditable and revocable</li>
|
||||
</ul>
|
||||
|
||||
<h3>Filesystem Abstraction</h3>
|
||||
<ul>
|
||||
<li>No global file system</li>
|
||||
<li>Programs receive only memory buffers with scoped access</li>
|
||||
<li>Read/write must go through kernel-mapped tokens</li>
|
||||
</ul>
|
||||
|
||||
<h3>Driver Isolation</h3>
|
||||
<ul>
|
||||
<li>Drivers are userland processes only</li>
|
||||
<li>No direct port I/O or DMA access</li>
|
||||
<li>Hardware is accessed via kernel-exposed capability channels</li>
|
||||
</ul>
|
||||
|
||||
<h3>IPC</h3>
|
||||
<ul>
|
||||
<li>All inter-process communication is routed via the kernel</li>
|
||||
<li>Uses named ports and token-authenticated message queues</li>
|
||||
<li>No shared memory by default</li>
|
||||
</ul>
|
||||
|
||||
<h3>Future Additions</h3>
|
||||
<ul>
|
||||
<li>Deterministic scheduler</li>
|
||||
<li>Audit trail of all token activity</li>
|
||||
<li>Formal capability typing system</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>Philosophy</h2>
|
||||
<p>This OS is not a POSIX clone. It is a deterministic, capability-secure, user-controlled computing environment built to reject legacy complexity and embrace verifiable simplicity.</p>
|
||||
</body>
|
||||
</html>
|
||||
172
docs/sterling.html
Normal file
172
docs/sterling.html
Normal file
@ -0,0 +1,172 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Sterling Language Documentation</title>
|
||||
<style>
|
||||
body { font-family: monospace; background: #0f0f0f; color: #f0f0f0; padding: 2rem; }
|
||||
h1, h2, h3 { color: #00ffe0; }
|
||||
pre { background: #1a1a1a; padding: 1rem; overflow-x: auto; }
|
||||
code { color: #d0d0ff; }
|
||||
a { color: #00aaff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Sterling Language Documentation</h1>
|
||||
<p>Version: <code>0.1.0-alpha</code></p>
|
||||
|
||||
<h2>Overview</h2>
|
||||
<p>Sterling is a low-level, strongly typed, systems programming language designed for performance, ABI stability, C interoperability, and full control over memory and hardware. It supports metaprogramming, hot-reloading, inline and raw assembly, and is built for multi-file compilation and dynamic linking.</p>
|
||||
|
||||
<h3>This Document is a work in progress, features are not yet implemented and i use this as a design document to stay true to my vision</h3>
|
||||
|
||||
<h2>File Extensions</h2>
|
||||
<ul>
|
||||
<li>Source files: <code>.stg</code></li>
|
||||
<li>Header files: <code>.sth</code> <em>(placeholder, subject to change)</em></li>
|
||||
</ul>
|
||||
|
||||
<h2>Function Qualifiers</h2>
|
||||
<p>Every function must declare its linkage explicitly:</p>
|
||||
|
||||
<pre><code>
|
||||
fn // globally visible, default linkage
|
||||
fn_static // translation unit-local only
|
||||
fn_export // must be exported to dynlib/staticlib
|
||||
fn_extern // declared but defined elsewhere
|
||||
fn_inline // inline-only, no symbol emitted
|
||||
fn_asm // raw assembly function, globally visible
|
||||
fn_static_asm // raw assembly function, TU-local only
|
||||
</code></pre>
|
||||
|
||||
<h2>Function Syntax</h2>
|
||||
<p>All functions must explicitly declare their return type. The only exception is <code>void</code>, which may be omitted for brevity when no return value is intended.</p>
|
||||
|
||||
<pre><code>
|
||||
fn u32 add(u32 a, u32 b) {
|
||||
return (a + b);
|
||||
}
|
||||
|
||||
fn_extern i32 printf(const char* fmt, ...);
|
||||
|
||||
fn_inline u32 max(u32 a, u32 b) {
|
||||
return ((a > b) ? a : b);
|
||||
}
|
||||
|
||||
fn exit() {
|
||||
// equivalent to fn void exit()
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<h2>Assembly Functions</h2>
|
||||
<p>Write raw x86_64 assembly using <code>fn_asm</code> or <code>fn_static_asm</code>. Symbol, section, and global declaration are implicit.</p>
|
||||
|
||||
<pre><code>
|
||||
fn_asm void* memset(void* dst, u8 value, u64 size) {
|
||||
test rdx, rdx
|
||||
je .done
|
||||
|
||||
mov rax, rsi
|
||||
mov rdi, rdi
|
||||
mov rcx, rdx
|
||||
|
||||
rep stosb
|
||||
|
||||
.done:
|
||||
mov rax, rdi
|
||||
ret
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<h2>Syscalls</h2>
|
||||
<p>System calls are allowed via <code>fn_asm</code> or wrapped using concrete ABI-aware interfaces. Example:</p>
|
||||
|
||||
<pre><code>
|
||||
fn_asm void exit() {
|
||||
mov rax, 60 ; syscall: exit
|
||||
mov rdi, 0 ; exit code
|
||||
syscall
|
||||
ret
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<h2>Types</h2>
|
||||
<p>Sterling supports explicitly sized, ABI-stable primitive types. Signed and unsigned integer types are defined as follows:</p>
|
||||
|
||||
<pre><code>
|
||||
i8, i16, i32, i64 // signed integers
|
||||
u8, u16, u32, u64 // unsigned integers
|
||||
f32, f64 // 32-bit and 64-bit IEEE floats
|
||||
bool // 1-byte boolean, 0 or 1 only
|
||||
char // 1-byte character (UTF-8)
|
||||
</code></pre>
|
||||
|
||||
<p>Pointer types:</p>
|
||||
|
||||
<pre><code>
|
||||
T* // Pointer to type T
|
||||
ptr* // Special pointer with implicit coercion allowed (e.g., for GC, reflective systems)
|
||||
void* // Opaque pointer with explicit cast required
|
||||
</code></pre>
|
||||
|
||||
<p>All types have explicitly defined size and alignment. Structs support default values and zero-initialization rules:</p>
|
||||
|
||||
<pre><code>
|
||||
typedef struct {
|
||||
u32 x = 5;
|
||||
u32 y;
|
||||
} vec2u;
|
||||
|
||||
vec2u a = {}; // x = 5, y = 0
|
||||
vec2u b = {0}; // x = 0, y = 0
|
||||
vec2u c; // x = 0, y = 0 (default zero-init)
|
||||
</code></pre>
|
||||
|
||||
<p>To opt out of default zero-initialization:</p>
|
||||
|
||||
<pre><code>
|
||||
@raw u32 raw_val; // uninitialized
|
||||
</code></pre>
|
||||
|
||||
<h2>Memory Model</h2>
|
||||
<p>Sterling uses explicit, manual memory management by default. All variables are zero-initialized unless explicitly marked with <code>@raw</code>. Heap allocation is done via standard system or custom allocators.</p>
|
||||
<ul>
|
||||
<li><strong>Stack</strong>: Local automatic variables</li>
|
||||
<li><strong>Heap</strong>: malloc/free or custom allocators</li>
|
||||
<li><strong>Zero-cost abstraction</strong>: structs and stack values are passed by value unless explicitly passed by pointer</li>
|
||||
</ul>
|
||||
<p>Alignment and packing are controllable per type (TBD syntax). All layout is predictable and optimized for cache behavior. There are no hidden fields, vtables, or RTTI overhead.</p>
|
||||
|
||||
<h2>Operating System Development Features</h2>
|
||||
<ul>
|
||||
<li>Direct register access: <code>reg.rax</code>, <code>reg.cr3</code>, etc.</li>
|
||||
<li>Memory barriers: <code>memory_fence_acquire()</code>, <code>memory_fence_release()</code></li>
|
||||
<li>Segment descriptor support: GDT, IDT, TSS descriptors definable via built-in types</li>
|
||||
<li>Interrupt handler definitions: <code>fn_isr</code> for IRQ, <code>fn_trap</code> for fault handlers</li>
|
||||
<li>Syscall traps: <code>fn_syscall</code> with ABI-safe handling</li>
|
||||
<li>No external ASM required: use <code>fn_asm</code> to write boot routines and context switches inline</li>
|
||||
<li>Inline port I/O: <code>outb(port, val)</code>, <code>inw(port)</code>, etc.</li>
|
||||
<li>MSR and control register access: readable and writable constants like <code>CR0_PG</code>, <code>MSR_EFER</code></li>
|
||||
<li>Binary blob inclusion: <code>embed_binary("boot.bin")</code></li>
|
||||
<li>Freestanding boot targets: no runtime required, bootloader/kernels fully supported</li>
|
||||
</ul>
|
||||
|
||||
<h2>Metaprogramming</h2>
|
||||
<p><em>TODO: Describe 'meta' keyword, templating, compile-time codegen, restrictions on type inference.</em></p>
|
||||
|
||||
<h2>ABI and Interop</h2>
|
||||
<p><em>TODO: Specify ABI model (System V AMD64), calling convention details, struct/pointer representation rules.</em></p>
|
||||
|
||||
<h2>Threading</h2>
|
||||
<p><em>TODO: Describe standard threading model, scheduler integration, context switching, green threads API.</em></p>
|
||||
|
||||
<h2>Graphics and Rendering</h2>
|
||||
<p><em>TODO: Describe native rendering interface, GPU abstraction layer, and access to OpenGL/DirectX backends.</em></p>
|
||||
|
||||
<h2>Build and Compilation Model</h2>
|
||||
<p><em>TODO: AOT compilation, linker behavior, multi-file project structure, module system (if any).</em></p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
12
kernel/LICENSE
Normal file
12
kernel/LICENSE
Normal file
@ -0,0 +1,12 @@
|
||||
0BSD License
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
19
sterling/LICENSE
Normal file
19
sterling/LICENSE
Normal file
@ -0,0 +1,19 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
Copyright 2025 Carle-Margueritte Alexandre
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
124
sterling/README.md
Normal file
124
sterling/README.md
Normal file
@ -0,0 +1,124 @@
|
||||
# Sterling
|
||||
|
||||
- another low level language
|
||||
|
||||
### things to add:
|
||||
|
||||
- the other day i forgot what but i had an idea about something to implement in the compiler that would be neat but not present in c
|
||||
- also need to be able to interface directly with assembly
|
||||
- also let the compiller trim unused symbole
|
||||
- adding a preprocessor to allow an include to not be completly used in the compiler
|
||||
- better for single header library, and also, add maybe a namespace or a directive to allow to multiple function to have the same name but give them different signature depending of their origin file exemple if their is a need to have two file that declare the same type, only specify what the user want, but it is to the user to know what they are doing, without needing to touch to the header file directly
|
||||
- anyway i see my point
|
||||
|
||||
## Vision and Goals
|
||||
|
||||
### Strict ABI standardization:
|
||||
- Every type, from built-in to user-defined, must have a well-defined, consistent size. This includes basic pointers (void*) and even complex dynamically sized types.
|
||||
|
||||
### Native Rendering Support:
|
||||
- The language should support both software rendering and GPU-accelerated graphics (e.g., via OpenGL or DirectX). This requires having a standardized interface or runtime layer that abstracts GPU calls while still allowing low-level access when needed.
|
||||
|
||||
### Cache-Friendly Data Structures:
|
||||
- Data layout in memory will be optimized for cache efficiency. This implies control over alignment, packing, and predictable memory layouts that might, for instance, allow SIMD operations or other low-level optimizations.
|
||||
|
||||
### Standard Threading Model:
|
||||
- A built-in threading library should be part of the standard.
|
||||
|
||||
### C-Interoperability:
|
||||
- The language must be designed from the ground up to interface smoothly with C libraries. This means standardizing calling conventions and possibly even having a translation layer for linking external C code.
|
||||
|
||||
___
|
||||
|
||||
## 1. Language Design
|
||||
|
||||
- low-level enough to manage memory and hardware directly (like C)
|
||||
- high-level enough to be safe and productive (optional but desirable)
|
||||
- well-specified, with a clear grammar and semantics
|
||||
|
||||
- manual memory management
|
||||
- dtrong type system (static typing, ideally with type inference for ergonomics)
|
||||
- interfacing with system calls and external libraries
|
||||
- compilation model (AOT, also look at meta programming)
|
||||
- it should absolutly not look or feel like c++.
|
||||
|
||||
- and it is not a plain copy of c also i will take some inspiration from holyc, it should not have oop at all
|
||||
|
||||
|
||||
## 2. Portable Compiler
|
||||
|
||||
- can target multiple architectures: x86_64, ARM, RISC-V, MIPS. (for starter x64 and ARM)
|
||||
- outputs native binaries, or optionally transpiles to C or LLVM IR
|
||||
- is self-hosted, eventually (bootstraps itself)
|
||||
- has cross-compilation built in
|
||||
- need to look into backend (LLVM or Cranelift) or build myself one
|
||||
|
||||
## 3. Build System
|
||||
|
||||
- it should be really straightforware, kinda like makefile
|
||||
|
||||
- dependency management.
|
||||
- cross-compilation support. (gcc )
|
||||
- linker. (gnu ld)
|
||||
- assembler. (gnu as)
|
||||
- debugger. (gnu db)
|
||||
|
||||
## 4. OS Abstraction Layer
|
||||
|
||||
- each OS has its own api:
|
||||
- syscalls.
|
||||
- file systems.
|
||||
- I/O.
|
||||
- threading.
|
||||
|
||||
- first i will aim for linux (i will dev on sleepeelinux (my own minimal operating system UwU))
|
||||
- runtime library (like libc musl) that wraps OS specifics into a unified API
|
||||
- fallback implementations for exotic or minimal platforms (embedded)
|
||||
|
||||
## 5. Standard Library
|
||||
|
||||
- data structures.
|
||||
- string handling.
|
||||
- math.
|
||||
- file I/O.
|
||||
- networking.
|
||||
- vulkan abstraction layer (i hate vulkan naming)
|
||||
|
||||
## 6. Testing Across Platforms
|
||||
|
||||
- i need to ensure deterministic builds
|
||||
- ABI compatibility
|
||||
- good error messages
|
||||
|
||||
## 7. Active Community and Contributions
|
||||
|
||||
- no fork you all, it will be open source, but most people are bad at programming so no if you want to work on it fork it -_-
|
||||
|
||||
#### ok UwU, if you really want to help ^^:
|
||||
|
||||
- undefined behavior are a nono.
|
||||
- new version should not break old behavior, it need to be robust so that people that write in 20year can use code from today
|
||||
- binary compatibility with system libraries or foreign function interfaces (FFI).
|
||||
- platform-specific optimizations. if a feature aim for a platforme, optimize it for it.
|
||||
- designing something portable and performant today is hard but maintaining that over decades is harder so yeah good look <3
|
||||
|
||||
___
|
||||
|
||||
# LANGUAGE DESIGN DOCUMENT
|
||||
|
||||
## Key Compiler Rules (Strict)
|
||||
|
||||
- Meta functions only instantiate for primitives or explicitly whitelisted types
|
||||
- Struct types must be manually specialized
|
||||
- Function names must be unique in the global symbol table after instantiation
|
||||
- No overloads: function + type combo must be deterministic
|
||||
|
||||
### Advantages of This Model
|
||||
|
||||
- No ambiguity: Instantiation only allowed when rules are met
|
||||
- Strict typing: Prevents C++-style template bloat or implicit struct operations
|
||||
- C compatibility: Resulting functions look like plain C
|
||||
- Low-level: You control when, how, and what gets generated
|
||||
|
||||
- my idea isn't to recreate the wheel but expand on thing that i like without falling into what c++ or other c inspired lang are
|
||||
- for now i am just writing idea, i'll need a lot more work to have a robust design, i am not better than other, i am more flawed, but i'll aim for self improvement
|
||||
199
sterling/exemple/exemple.stg
Normal file
199
sterling/exemple/exemple.stg
Normal file
@ -0,0 +1,199 @@
|
||||
it should look more like c, as i want my compiler to be able to compile c
|
||||
|
||||
#include <io.sterling>//sterling is the name of the language, but i need to think of a file extension name that doesn't conflict with other format
|
||||
#include <string.h>//this should work
|
||||
|
||||
u32 add(u32 a, u32 b) {
|
||||
return (a + b);
|
||||
}
|
||||
|
||||
// also i should be able as the user to define
|
||||
|
||||
typedef struct {
|
||||
u32 test = 12;
|
||||
} new_struct;
|
||||
// if new_struct struct = {0}; then all data even default init are set to 0
|
||||
// but if new_struct struct = {}; then all data but default init are set to 0
|
||||
|
||||
//also pointer should work like c, but void* shouldn't be the same as ptr*
|
||||
//i don't know what i could do, but i would like for ptr* to allow for implicite data cast, but void* should be explicit
|
||||
|
||||
meta define_add(T);
|
||||
T add(T a, T b) {
|
||||
return (a + b);
|
||||
}
|
||||
//the issue i have here is it need to have an explicit overload if T is a structure, and i don't really like it, could lead to a c++ like language with too many undefined behavior, what could be a better approach ?
|
||||
|
||||
|
||||
#include <io.stgh>//for stg header but i could also just use .stg and have the possibility to include stg file as header
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
u32 x = 1;
|
||||
u32 y = 2;
|
||||
} vec2;
|
||||
|
||||
typedef struct {
|
||||
u32 x;
|
||||
u32 y;
|
||||
} vec2_raw;
|
||||
|
||||
u32 add(u32 a, u32 b) {
|
||||
return (a + b);
|
||||
}
|
||||
|
||||
vec2_raw make_raw(u32 a, u32 b) {
|
||||
return (vec2_raw){ a, b };
|
||||
}
|
||||
|
||||
void* memcpy_explicit(void* dst, void* src, u32 n) {
|
||||
// must explicitly cast outside
|
||||
return memcpy(dst, src, n);
|
||||
}
|
||||
|
||||
fn copy(ptr* dst, ptr* src, u32 n) {
|
||||
// compiler auto-casts any ptr* to void* internally
|
||||
memcpy(dst, src, n);
|
||||
}
|
||||
|
||||
meta define_add(T);
|
||||
T add(T a, T b) {
|
||||
return (a + b);
|
||||
}
|
||||
|
||||
// specialization for vec2
|
||||
meta define_add(vec2);
|
||||
vec2 add(vec2 a, vec2 b) {
|
||||
return (vec2){ a.x + b.x, a.y + b.y };
|
||||
}
|
||||
|
||||
fn main() -> u32 {
|
||||
vec2 a = {}; // defaults apply
|
||||
vec2 b = {0}; // defaults ignored, all zero
|
||||
|
||||
vec2 result = add(a, b);
|
||||
|
||||
u32* data = 0;
|
||||
copy(data, data, 4); // OK
|
||||
memcpy_explicit((void*)data, (void*)data, 4); // must cast
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn_asm exit() {
|
||||
section .text
|
||||
global exit
|
||||
exit:
|
||||
mov rax, 60 ; syscall for exit
|
||||
mov rdi, 0 ; exit code
|
||||
syscall
|
||||
ret
|
||||
}
|
||||
|
||||
/*
|
||||
rdi: dst
|
||||
rsi: value
|
||||
rdx: size
|
||||
Returns in rax: dst
|
||||
*/
|
||||
/* implicit
|
||||
section .text
|
||||
global <symbol>
|
||||
memset:
|
||||
*/
|
||||
fn_asm memset(void* dst, u8 value, u64 size) {
|
||||
test rdx, rdx
|
||||
je .done
|
||||
|
||||
mov rax, rsi ; value
|
||||
mov rdi, rdi ; dst
|
||||
mov rcx, rdx ; size
|
||||
|
||||
rep stosb
|
||||
|
||||
.done:
|
||||
mov rax, rdi ; return dst
|
||||
ret
|
||||
}
|
||||
//This uses the rep stosb instruction to rapidly write bytes into memory.
|
||||
|
||||
/*
|
||||
rdi: void** old_sp — destination to store current rsp
|
||||
rsi: void* new_sp — new stack pointer to switch into
|
||||
No return value (control flow continues on new stack)
|
||||
*/
|
||||
fn_asm context_switch(void** old_sp, void* new_sp) {
|
||||
mov [rdi], rsp ; save current stack pointer to *old_sp
|
||||
mov rsp, rsi ; load new stack pointer
|
||||
ret
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
rdi: dst
|
||||
rsi: value
|
||||
rdx: size
|
||||
Returns in rax: dst
|
||||
*/
|
||||
/* implicit
|
||||
section .text
|
||||
memset:
|
||||
*/
|
||||
fn_static_asm memset(void* dst, u8 value, u64 size) {
|
||||
test rdx, rdx
|
||||
je .done
|
||||
|
||||
mov rax, rsi ; value
|
||||
mov rdi, rdi ; dst
|
||||
mov rcx, rdx ; size
|
||||
|
||||
rep stosb
|
||||
|
||||
.done:
|
||||
mov rax, rdi ; return dst
|
||||
ret
|
||||
}
|
||||
//This uses the rep stosb instruction to rapidly write bytes into memory.
|
||||
|
||||
/*
|
||||
| Keyword | Description |
|
||||
| --------------- | ---------------------------------------------------------------------- |
|
||||
| `fn` | Required for every function definition |
|
||||
| `fn_inline` | Inline-only function, callable in the same TU |
|
||||
| `fn_static` | Internal linkage (only visible in current TU) |
|
||||
| `fn_extern` | Declaration only; expects symbol at link time |
|
||||
| `fn_export` | Visible outside, exported in shared/static libs |
|
||||
| `fn_asm` | Assembly-defined function, globally visible unless otherwise specified |
|
||||
| `fn_static_asm` | Assembly-defined, internal linkage (hidden from linker) |
|
||||
*/
|
||||
|
||||
//Keyword Examples
|
||||
|
||||
// header file (user_math.stgh)
|
||||
fn_extern add(u32, u32);
|
||||
fn_inline max(u32 a, u32 b) {
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
// libmath.stg
|
||||
fn_export add(u32 a, u32 b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
// internal use only
|
||||
fn_static log2_floor(u32 x) {
|
||||
// implementation
|
||||
}
|
||||
|
||||
// inline asm
|
||||
fn_asm fast_add(u32 a, u32 b) {
|
||||
mov eax, edi
|
||||
add eax, esi
|
||||
ret
|
||||
}
|
||||
|
||||
// internal-only asm
|
||||
fn_static_asm zero_block(void* dst, u64 size) {
|
||||
rep stosb
|
||||
ret
|
||||
}
|
||||
96
sterling/source/ast.h
Normal file
96
sterling/source/ast.h
Normal file
@ -0,0 +1,96 @@
|
||||
enum NodeKind {
|
||||
NODE_FUNCTION,
|
||||
NODE_VAR_DECL,
|
||||
NODE_TYPEDEF,
|
||||
NODE_STRUCT,
|
||||
NODE_RETURN,
|
||||
NODE_BINARY_OP,
|
||||
NODE_LITERAL,
|
||||
NODE_IDENTIFIER,
|
||||
NODE_CALL,
|
||||
NODE_BLOCK,
|
||||
}
|
||||
|
||||
struct ASTNode {
|
||||
NodeKind kind;
|
||||
union {
|
||||
FunctionNode fn;
|
||||
VarDeclNode var;
|
||||
TypedefNode td;
|
||||
StructNode str;
|
||||
ExprNode expr;
|
||||
BlockNode block;
|
||||
}
|
||||
}
|
||||
|
||||
// Function
|
||||
struct FunctionNode {
|
||||
String name;
|
||||
String return_type;
|
||||
List<VarDeclNode> params;
|
||||
BlockNode body;
|
||||
bool is_inline;
|
||||
bool is_static;
|
||||
bool is_export;
|
||||
bool is_extern;
|
||||
bool is_asm;
|
||||
}
|
||||
|
||||
// Variable declaration
|
||||
struct VarDeclNode {
|
||||
String name;
|
||||
String type;
|
||||
ExprNode* init; // optional
|
||||
bool is_raw;
|
||||
}
|
||||
|
||||
// Block
|
||||
struct BlockNode {
|
||||
List<ASTNode> statements;
|
||||
}
|
||||
|
||||
// Typedef
|
||||
struct TypedefNode {
|
||||
String alias;
|
||||
String type;
|
||||
}
|
||||
|
||||
// Struct
|
||||
struct StructNode {
|
||||
String name;
|
||||
List<VarDeclNode> fields;
|
||||
}
|
||||
|
||||
// Expression
|
||||
enum ExprKind {
|
||||
EXPR_LITERAL, EXPR_IDENTIFIER, EXPR_BINARY, EXPR_CALL, EXPR_CAST
|
||||
}
|
||||
|
||||
struct ExprNode {
|
||||
ExprKind kind;
|
||||
union {
|
||||
LiteralNode lit;
|
||||
String ident;
|
||||
BinaryExprNode bin;
|
||||
CallExprNode call;
|
||||
CastExprNode cast;
|
||||
}
|
||||
}
|
||||
|
||||
// Binary op
|
||||
struct BinaryExprNode {
|
||||
String op;
|
||||
ExprNode* lhs;
|
||||
ExprNode* rhs;
|
||||
}
|
||||
|
||||
// Function call
|
||||
struct CallExprNode {
|
||||
String callee;
|
||||
List<ExprNode> args;
|
||||
}
|
||||
|
||||
// Literal
|
||||
struct LiteralNode {
|
||||
String value; // numeric, char, string
|
||||
}
|
||||
94
sterling/source/codegen.c
Normal file
94
sterling/source/codegen.c
Normal file
@ -0,0 +1,94 @@
|
||||
void generate(ASTNode* node) {
|
||||
switch (node.kind) {
|
||||
case NODE_FUNCTION:
|
||||
gen_function(&node.fn);
|
||||
break;
|
||||
case NODE_TYPEDEF:
|
||||
printf("typedef %s %s;\n", node.td.type, node.td.alias);
|
||||
break;
|
||||
case NODE_STRUCT:
|
||||
gen_struct(&node.str);
|
||||
break;
|
||||
case NODE_VAR_DECL:
|
||||
gen_var_decl(&node.var);
|
||||
break;
|
||||
case NODE_BLOCK:
|
||||
gen_block(&node.block);
|
||||
break;
|
||||
default:
|
||||
error("unsupported node");
|
||||
}
|
||||
}
|
||||
|
||||
void gen_function(FunctionNode* fn) {
|
||||
if (fn->is_inline) printf("inline ");
|
||||
else if (fn->is_static) printf("static ");
|
||||
else if (fn->is_extern) printf("extern ");
|
||||
else if (fn->is_export) printf("__attribute__((visibility(\"default\"))) ");
|
||||
|
||||
printf("%s %s(", fn->return_type, fn->name);
|
||||
for (i = 0; i < fn->params.len; i++) {
|
||||
gen_var_decl(&fn->params[i]);
|
||||
if (i < fn->params.len - 1) printf(", ");
|
||||
}
|
||||
printf(") ");
|
||||
gen_block(&fn->body);
|
||||
}
|
||||
|
||||
void gen_block(BlockNode* block) {
|
||||
printf("{\n");
|
||||
for (stmt in block.statements) {
|
||||
generate(stmt);
|
||||
}
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
void gen_var_decl(VarDeclNode* var) {
|
||||
printf("%s %s", var->type, var->name);
|
||||
if (var->init != NULL) {
|
||||
printf(" = ");
|
||||
gen_expr(var->init);
|
||||
}
|
||||
printf(";");
|
||||
}
|
||||
|
||||
void gen_struct(StructNode* str) {
|
||||
printf("typedef struct {\n");
|
||||
for (field in str.fields) {
|
||||
printf("\t%s %s", field.type, field.name);
|
||||
if (field.init != NULL) {
|
||||
printf(" = ");
|
||||
gen_expr(field.init);
|
||||
}
|
||||
printf(";\n");
|
||||
}
|
||||
printf("} %s;\n", str.name);
|
||||
}
|
||||
|
||||
void gen_expr(ExprNode* expr) {
|
||||
switch (expr.kind) {
|
||||
case EXPR_LITERAL:
|
||||
printf("%s", expr.lit.value);
|
||||
break;
|
||||
case EXPR_IDENTIFIER:
|
||||
printf("%s", expr.ident);
|
||||
break;
|
||||
case EXPR_BINARY:
|
||||
gen_expr(expr.bin.lhs);
|
||||
printf(" %s ", expr.bin.op);
|
||||
gen_expr(expr.bin.rhs);
|
||||
break;
|
||||
case EXPR_CALL:
|
||||
printf("%s(", expr.call.callee);
|
||||
for (i = 0; i < expr.call.args.len; i++) {
|
||||
gen_expr(expr.call.args[i]);
|
||||
if (i < expr.call.args.len - 1) printf(", ");
|
||||
}
|
||||
printf(")");
|
||||
break;
|
||||
case EXPR_CAST:
|
||||
printf("(%s)", expr.cast.to_type);
|
||||
gen_expr(expr.cast.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
113
sterling/source/lexer.c
Normal file
113
sterling/source/lexer.c
Normal file
@ -0,0 +1,113 @@
|
||||
enum TokenType {
|
||||
TOK_EOF, TOK_IDENTIFIER, TOK_INTEGER, TOK_STRING, TOK_CHAR,
|
||||
TOK_FN, TOK_RETURN, TOK_STRUCT, TOK_TYPEDEF,
|
||||
TOK_TYPE_U8, TOK_TYPE_U32, // ... add all types
|
||||
TOK_FN_STATIC, TOK_FN_EXPORT, // ... all fn variants
|
||||
TOK_LBRACE, TOK_RBRACE, TOK_LPAREN, TOK_RPAREN,
|
||||
TOK_COMMA, TOK_SEMICOLON, TOK_STAR, TOK_EQUAL,
|
||||
TOK_PLUS, TOK_MINUS, TOK_SLASH, TOK_BANG, TOK_ARROW,
|
||||
// ...
|
||||
};
|
||||
|
||||
struct Token {
|
||||
TokenType type;
|
||||
char* lexeme;
|
||||
int line;
|
||||
};
|
||||
|
||||
struct Lexer {
|
||||
char* src;
|
||||
int pos;
|
||||
int line;
|
||||
};
|
||||
|
||||
char peek(Lexer* l) {
|
||||
return l->src[l->pos];
|
||||
}
|
||||
|
||||
char advance(Lexer* l) {
|
||||
if (l->src[l->pos] == '\n') l->line++;
|
||||
return l->src[l->pos++];
|
||||
}
|
||||
|
||||
bool match(Lexer* l, char expected) {
|
||||
if (l->src[l->pos] != expected) return false;
|
||||
l->pos++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void skip_whitespace_and_comments(Lexer* l) {
|
||||
while (true) {
|
||||
char c = peek(l);
|
||||
if (c == ' ' || c == '\t' || c == '\r' || c == '\n') advance(l);
|
||||
else if (c == '/' && l->src[l->pos + 1] == '/') {
|
||||
while (peek(l) != '\n' && peek(l) != '\0') advance(l);
|
||||
}
|
||||
else if (c == '/' && l->src[l->pos + 1] == '*') {
|
||||
advance(l); advance(l); // skip /*
|
||||
while (!(peek(l) == '*' && l->src[l->pos + 1] == '/')) {
|
||||
if (peek(l) == '\0') error("unterminated comment");
|
||||
advance(l);
|
||||
}
|
||||
advance(l); advance(l); // skip */
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
Token identifier_or_keyword(Lexer* l, int start) {
|
||||
while (isalnum(peek(l)) || peek(l) == '_') advance(l);
|
||||
char* text = slice(l->src + start, l->pos - start);
|
||||
|
||||
// check keyword map
|
||||
TokenType type = lookup_keyword(text); // use hash or strcmp
|
||||
return Token { type, text, l->line };
|
||||
}
|
||||
|
||||
Token number(Lexer* l, int start) {
|
||||
while (isdigit(peek(l))) advance(l);
|
||||
char* text = slice(l->src + start, l->pos - start);
|
||||
return Token { TOK_INTEGER, text, l->line };
|
||||
}
|
||||
|
||||
Token string(Lexer* l) {
|
||||
advance(l); // skip opening quote
|
||||
int start = l->pos;
|
||||
while (peek(l) != '"' && peek(l) != '\0') {
|
||||
if (peek(l) == '\\') advance(l); // escape
|
||||
advance(l);
|
||||
}
|
||||
char* text = slice(l->src + start, l->pos - start);
|
||||
if (peek(l) != '"') error("unterminated string");
|
||||
advance(l); // closing quote
|
||||
return Token { TOK_STRING, text, l->line };
|
||||
}
|
||||
|
||||
Token next_token(Lexer* l) {
|
||||
skip_whitespace_and_comments(l);
|
||||
int start = l->pos;
|
||||
|
||||
char c = advance(l);
|
||||
switch (c) {
|
||||
case '\0': return Token { TOK_EOF, "", l->line };
|
||||
case '{': return Token { TOK_LBRACE, "{", l->line };
|
||||
case '}': return Token { TOK_RBRACE, "}", l->line };
|
||||
case '(': return Token { TOK_LPAREN, "(", l->line };
|
||||
case ')': return Token { TOK_RPAREN, ")", l->line };
|
||||
case ',': return Token { TOK_COMMA, ",", l->line };
|
||||
case ';': return Token { TOK_SEMICOLON, ";", l->line };
|
||||
case '*': return Token { TOK_STAR, "*", l->line };
|
||||
case '=': return Token { TOK_EQUAL, "=", l->line };
|
||||
case '+': return Token { TOK_PLUS, "+", l->line };
|
||||
case '-':
|
||||
if (match(l, '>')) return Token { TOK_ARROW, "->", l->line };
|
||||
else return Token { TOK_MINUS, "-", l->line };
|
||||
case '/': return Token { TOK_SLASH, "/", l->line };
|
||||
case '!': return Token { TOK_BANG, "!", l->line };
|
||||
case '"': return string(l);
|
||||
default:
|
||||
if (isalpha(c) || c == '_') return identifier_or_keyword(l, start);
|
||||
if (isdigit(c)) return number(l, start);
|
||||
error("unexpected character");
|
||||
}
|
||||
}
|
||||
116
sterling/source/parsing.c
Normal file
116
sterling/source/parsing.c
Normal file
@ -0,0 +1,116 @@
|
||||
#include "ast.h"
|
||||
|
||||
struct Parser {
|
||||
Token* tokens;
|
||||
int current;
|
||||
}
|
||||
|
||||
Token peek(Parser* p);
|
||||
Token advance(Parser* p);
|
||||
bool match(Parser* p, TokenKind kind);
|
||||
bool expect(Parser* p, TokenKind kind, const char* error);
|
||||
bool is_at_end(Parser* p);
|
||||
|
||||
List<ASTNode> parse_program(Parser* p) {
|
||||
List<ASTNode> nodes;
|
||||
|
||||
while (!is_at_end(p)) {
|
||||
nodes.append(parse_toplevel(p));
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
ASTNode parse_toplevel(Parser* p) {
|
||||
if (match(p, KW_FN)) return parse_function(p);
|
||||
if (match(p, KW_TYPEDEF)) return parse_typedef(p);
|
||||
if (match(p, KW_STRUCT)) return parse_struct(p);
|
||||
error("Unexpected top-level declaration");
|
||||
}
|
||||
|
||||
ASTNode parse_function(Parser* p) {
|
||||
ASTNode node;
|
||||
node.kind = NODE_FUNCTION;
|
||||
|
||||
FunctionNode fn;
|
||||
|
||||
// Qualifiers (optional)
|
||||
while (match(p, KW_STATIC) || match(p, KW_EXPORT) || match(p, KW_INLINE) || match(p, KW_EXTERN) || match(p, KW_ASM)) {
|
||||
switch (previous(p).kind) {
|
||||
case KW_STATIC: fn.is_static = true; break;
|
||||
case KW_EXPORT: fn.is_export = true; break;
|
||||
case KW_INLINE: fn.is_inline = true; break;
|
||||
case KW_EXTERN: fn.is_extern = true; break;
|
||||
case KW_ASM: fn.is_asm = true; break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return type
|
||||
fn.return_type = expect_identifier(p);
|
||||
|
||||
// Name
|
||||
fn.name = expect_identifier(p);
|
||||
|
||||
// Parameters
|
||||
expect(p, TOKEN_LPAREN, "Expected '(' after function name");
|
||||
while (!match(p, TOKEN_RPAREN)) {
|
||||
fn.params.append(parse_var_decl(p));
|
||||
if (!match(p, TOKEN_RPAREN)) expect(p, TOKEN_COMMA, "Expected ',' between parameters");
|
||||
}
|
||||
|
||||
// Body or semicolon (extern only)
|
||||
if (fn.is_extern) {
|
||||
expect(p, TOKEN_SEMICOLON, "Expected ';' after extern declaration");
|
||||
fn.body = NULL;
|
||||
} else {
|
||||
fn.body = parse_block(p);
|
||||
}
|
||||
|
||||
node.fn = fn;
|
||||
return node;
|
||||
}
|
||||
|
||||
VarDeclNode parse_var_decl(Parser* p) {
|
||||
VarDeclNode var;
|
||||
var.type = expect_identifier(p);
|
||||
var.name = expect_identifier(p);
|
||||
|
||||
if (match(p, TOKEN_ASSIGN)) {
|
||||
var.init = parse_expression(p);
|
||||
}
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
ASTNode parse_struct(Parser* p) {
|
||||
expect(p, KW_STRUCT, "Expected 'struct'");
|
||||
String name = expect_identifier(p);
|
||||
|
||||
expect(p, TOKEN_LBRACE, "Expected '{' for struct definition");
|
||||
|
||||
List<VarDeclNode> fields;
|
||||
while (!match(p, TOKEN_RBRACE)) {
|
||||
fields.append(parse_var_decl(p));
|
||||
expect(p, TOKEN_SEMICOLON, "Expected ';' after struct field");
|
||||
}
|
||||
|
||||
StructNode str = { .name = name, .fields = fields };
|
||||
ASTNode node = { .kind = NODE_STRUCT, .str = str };
|
||||
return node;
|
||||
}
|
||||
|
||||
BlockNode parse_block(Parser* p) {
|
||||
BlockNode block;
|
||||
|
||||
expect(p, TOKEN_LBRACE, "Expected '{'");
|
||||
while (!match(p, TOKEN_RBRACE)) {
|
||||
block.statements.append(parse_statement(p));
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
ExprNode* parse_expression(Parser* p);
|
||||
ExprNode* parse_primary(Parser* p);
|
||||
ExprNode* parse_binary(Parser* p, int min_prec);
|
||||
ExprNode* parse_call(Parser* p, ExprNode* callee);
|
||||
12
userland/LICENSE
Normal file
12
userland/LICENSE
Normal file
@ -0,0 +1,12 @@
|
||||
0BSD License
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
Loading…
x
Reference in New Issue
Block a user