pr 56
This commit is contained in:
parent
6732111328
commit
ad1650592d
@ -86,6 +86,7 @@ pub struct ParamNode {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct FnDeclNode {
|
||||
pub span: Span,
|
||||
pub vis: String,
|
||||
pub name: String,
|
||||
pub params: Vec<ParamNode>,
|
||||
pub ret: Option<Box<Node>>,
|
||||
|
||||
@ -40,12 +40,16 @@ impl SymbolCollector {
|
||||
}
|
||||
|
||||
fn collect_fn(&mut self, decl: &FnDeclNode) {
|
||||
// Top-level fn are always file-private in PBS v0
|
||||
let vis = match decl.vis.as_str() {
|
||||
"pub" => Visibility::Pub,
|
||||
"mod" => Visibility::Mod,
|
||||
_ => Visibility::FilePrivate,
|
||||
};
|
||||
let symbol = Symbol {
|
||||
name: decl.name.clone(),
|
||||
kind: SymbolKind::Function,
|
||||
namespace: Namespace::Value,
|
||||
visibility: Visibility::FilePrivate,
|
||||
visibility: vis,
|
||||
ty: None, // Will be resolved later
|
||||
is_host: false,
|
||||
span: decl.span,
|
||||
|
||||
@ -131,7 +131,7 @@ impl Parser {
|
||||
|
||||
fn parse_top_level_decl(&mut self) -> Result<Node, DiagnosticBundle> {
|
||||
match self.peek().kind {
|
||||
TokenKind::Fn => self.parse_fn_decl(),
|
||||
TokenKind::Fn => self.parse_fn_decl("file".to_string()),
|
||||
TokenKind::Pub | TokenKind::Mod | TokenKind::Declare | TokenKind::Service => self.parse_decl(),
|
||||
TokenKind::Invalid(ref msg) => {
|
||||
let code = if msg.contains("Unterminated string") {
|
||||
@ -160,7 +160,17 @@ impl Parser {
|
||||
match self.peek().kind {
|
||||
TokenKind::Service => self.parse_service_decl(vis.unwrap_or_else(|| "pub".to_string())),
|
||||
TokenKind::Declare => self.parse_type_decl(vis),
|
||||
_ => Err(self.error("Expected 'service' or 'declare'")),
|
||||
TokenKind::Fn => {
|
||||
let vis_str = vis.unwrap_or_else(|| "file".to_string());
|
||||
if vis_str == "pub" {
|
||||
return Err(self.error_with_code(
|
||||
"Functions cannot be public. They are always mod or file-private.",
|
||||
Some("E_RESOLVE_VISIBILITY"),
|
||||
));
|
||||
}
|
||||
self.parse_fn_decl(vis_str)
|
||||
}
|
||||
_ => Err(self.error("Expected 'service', 'declare', or 'fn'")),
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,7 +339,7 @@ impl Parser {
|
||||
}))
|
||||
}
|
||||
|
||||
fn parse_fn_decl(&mut self) -> Result<Node, DiagnosticBundle> {
|
||||
fn parse_fn_decl(&mut self, vis: String) -> Result<Node, DiagnosticBundle> {
|
||||
let start_span = self.consume(TokenKind::Fn)?.span;
|
||||
let name = self.expect_identifier()?;
|
||||
let params = self.parse_param_list()?;
|
||||
@ -351,6 +361,7 @@ impl Parser {
|
||||
|
||||
Ok(Node::FnDecl(FnDeclNode {
|
||||
span: Span::new(self.file_id, start_span.start, body_span.end),
|
||||
vis,
|
||||
name,
|
||||
params,
|
||||
ret: _ret,
|
||||
@ -1141,6 +1152,28 @@ fn good() {}
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_mod_fn() {
|
||||
let source = "mod fn test() {}";
|
||||
let mut parser = Parser::new(source, 0);
|
||||
let result = parser.parse_file().expect("mod fn should be allowed");
|
||||
if let Node::FnDecl(fn_decl) = &result.decls[0] {
|
||||
assert_eq!(fn_decl.vis, "mod");
|
||||
} else {
|
||||
panic!("Expected FnDecl");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_pub_fn() {
|
||||
let source = "pub fn test() {}";
|
||||
let mut parser = Parser::new(source, 0);
|
||||
let result = parser.parse_file();
|
||||
assert!(result.is_err(), "pub fn should be disallowed");
|
||||
let err = result.unwrap_err();
|
||||
assert!(err.diagnostics[0].message.contains("Functions cannot be public"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ast_json_snapshot() {
|
||||
let source = r#"
|
||||
|
||||
@ -203,10 +203,10 @@ Visibility is mandatory for services.
|
||||
### 3.4 Functions
|
||||
|
||||
```
|
||||
FnDecl ::= 'fn' Identifier ParamList ReturnType? ElseFallback? Block
|
||||
FnDecl ::= Visibility? 'fn' Identifier ParamList ReturnType? ElseFallback? Block
|
||||
```
|
||||
|
||||
Top‑level `fn` are always file‑private.
|
||||
Top‑level `fn` are `mod` or `file-private` (default). They cannot be `pub`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -202,7 +202,7 @@ The **value namespace** contains executable and runtime-visible symbols.
|
||||
Symbols in the value namespace are introduced by:
|
||||
|
||||
* `service`
|
||||
* top-level `fn` - always file-private.
|
||||
* top-level `fn` — `mod` or `file-private` (default).
|
||||
* top-level `let` are not allowed.
|
||||
|
||||
Rules:
|
||||
@ -360,9 +360,9 @@ Top-level `fn` declarations define reusable executable logic.
|
||||
|
||||
Rules:
|
||||
|
||||
* A top-level `fn` is always **file-private**.
|
||||
* A top-level `fn` cannot be declared as `mod` or `pub`.
|
||||
* A top-level `fn` is visible only within the file where it is declared.
|
||||
* A top-level `fn` is always **mod** or **file-private**.
|
||||
* A top-level `fn` cannot be declared as `pub`.
|
||||
* `fn` defaults to **file-private** visibility.
|
||||
|
||||
Example (VALID):
|
||||
|
||||
|
||||
@ -1,47 +1,3 @@
|
||||
## PR-13 — Build Plan v0: deterministic compilation order
|
||||
|
||||
**Why:** We need a stable, reproducible pipeline: compile dependencies first, then the root project.
|
||||
|
||||
### Scope
|
||||
|
||||
* Implement `prometeu_compiler::build::plan`:
|
||||
|
||||
* **Input:** `ResolvedGraph`
|
||||
* **Output:** `BuildPlan` with topologically sorted build steps
|
||||
* Each `BuildStep` MUST include:
|
||||
|
||||
* `project_id` — canonical project identity (`prometeu.json.name`)
|
||||
* `project_dir` — absolute or normalized path
|
||||
* `target` — `main` or `test`
|
||||
* `sources` — ordered list of `.pbs` source files (from `src/<target>/modules`)
|
||||
* `deps` — dependency edge map: `alias -> ProjectId`
|
||||
|
||||
### Determinism Rules (MANDATORY)
|
||||
|
||||
* Topological sort must be stable:
|
||||
|
||||
* when multiple nodes have indegree 0, choose by lexicographic `project_id`
|
||||
* `sources` list must be:
|
||||
|
||||
* discovered only under `src/<target>/modules`
|
||||
* sorted lexicographically by normalized relative path
|
||||
* `deps` must be stored/exported in deterministic order (e.g. `BTreeMap`)
|
||||
|
||||
### Deliverables
|
||||
|
||||
* `BuildPlan { steps: Vec<BuildStep> }`
|
||||
|
||||
### Tests
|
||||
|
||||
* topo ordering stable across runs
|
||||
* sources ordering stable regardless of filesystem order
|
||||
|
||||
### Acceptance
|
||||
|
||||
* BuildPlan is deterministic and contains all information needed to compile without further graph traversal.
|
||||
|
||||
---
|
||||
|
||||
## PR-14 — Compiler Output Format v0: emit per-project object module (intermediate)
|
||||
|
||||
**Why:** Linking requires a well-defined intermediate representation per project.
|
||||
|
||||
@ -641,6 +641,7 @@
|
||||
"start": 739,
|
||||
"end": 788
|
||||
},
|
||||
"vis": "file",
|
||||
"name": "add",
|
||||
"params": [
|
||||
{
|
||||
@ -742,6 +743,7 @@
|
||||
"start": 790,
|
||||
"end": 1180
|
||||
},
|
||||
"vis": "file",
|
||||
"name": "frame",
|
||||
"params": [],
|
||||
"ret": {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user