04-syntax

Level: beginner · Reading time: 20 min · Prerequisite: book/chapters/03-projet.html · Track: essential · Maturity: reviewed · Last review: 2026-05-09

TL;DR (5 lines)

  • Syntax is about shape before detail.
  • A valid block is the smallest useful teaching unit.
  • Statements and declarations belong to different layers.
  • Invalid examples should isolate shape errors.
  • The reader should leave able to recognize a healthy block instantly.

Frequent mistakes

  • Teaching surface tokens without explaining block shape.
  • Using syntax pages to comment every line instead of naming the pattern.
  • Confusing grammar shape with later semantic checks.

Prerequisites: book/chapters/03-projet.html. See also: book/chapters/03-projet.html, book/chapters/27-grammar.html, book/chapters/31-build-errors.html.

Concrete Problem

Syntax pages become noisy when they enumerate tokens without showing how a complete block is supposed to look.

Red Thread (Single Project)

One small block shows declarations, expressions, and returns in a single readable flow.

For what

This chapter helps the reader recognize valid Vitte shapes quickly.

Work in this chapter

You will read one valid block, map its parts to grammar roles, then inspect an invalid variant that breaks the shape.

Coherent example

space demo/syntax

proc compute(x: int, y: int) -> int {
  let sum: int = x + y
  if sum < 0 { give 0 }
  give sum
}

proc main(args: list[string]) -> int {
  give compute(1, 2)
}

export *

Complete examples

Each block below is a complete reading unit with its own boundary, data shape, and observable result.

Primary coherent example

This is the compact chapter anchor used by the surrounding explanation.

space demo/syntax

proc compute(x: int, y: int) -> int {
  let sum: int = x + y
  if sum < 0 { give 0 }
  give sum
}

proc main(args: list[string]) -> int {
  give compute(1, 2)
}

export *

Declaration and branch shape

This block keeps declarations, locals, branches, and final result easy to scan.

space examples/syntax/shape

proc clamp(value: int, max: int) -> int {
  let floor: int = 0
  if value < floor { give floor }
  if value > max { give max }
  give value
}

proc main(args: list[string]) -> int {
  give clamp(12, 10)
}

export *

Nested readable block

This example keeps a larger block readable without hiding the exit path.

space examples/syntax/nested

proc route(code: int) -> int {
  if code < 0 {
    give 10
  }
  if code == 0 {
    give 0
  }
  give 1
}

proc main(args: list[string]) -> int {
  give route(1)
}

export *

Immediate work for this chapter

  • Separate declarations, statements, expressions, and block boundaries.
  • Use one valid block that demonstrates the chapter shape without noise.
  • Make the malformed block fail at syntax shape, not business logic.
  • Keep the first code block complete and aligned with current Vitte docs syntax.
  • Keep the invalid block focused on one broken contract only.
  • Replace generic prose with one concrete rule visible in the code.
  • Keep every example small enough to review from top to bottom.

Chapter override: 04-syntax.html

Dedicated problem

This chapter must teach syntax as readable program shape. The reader should see where declarations, statements, expressions, and final results belong before learning advanced constructs.

Specific complete examples

Minimal block shape

One procedure keeps binding, guard, and final result in the canonical order.

space examples/syntax/minimal_block

proc clamp(value: int) -> int {
  let min: int = 0
  if value < min { give min }
  give value
}

proc main(args: list[string]) -> int {
  give clamp(3)
}

export *

Nested branch shape

A larger block remains readable because every branch returns a visible status.

space examples/syntax/nested_branch

proc route(code: int) -> int {
  if code < 0 {
    give 10
  }
  if code == 0 {
    give 0
  }
  give 1
}

proc main(args: list[string]) -> int {
  give route(5)
}

export *

Declaration then execution

Top-level declarations come before the procedure that makes behavior observable.

space examples/syntax/declaration_flow

const EXIT_OK: int = 0

proc status(enabled: bool) -> int {
  if not enabled { give 11 }
  give EXIT_OK
}

proc main(args: list[string]) -> int {
  give status(true)
}

export *

Risks and diagnostics

RiskDiagnostic signalAction
Incomplete blockA declaration or procedure body has no closed scope.Keep braces and final `give` visible.
Misplaced statementA local statement appears at module level.Separate top-level declarations from procedure bodies.
Ambiguous resultThe reader cannot locate the returned value.End the path with a clear `give`.

Review checklist

  • Top-level items are distinct from executable statements.
  • Each procedure has a visible result path.
  • The invalid example breaks syntax shape only.
  • Examples use current docs syntax and no obsolete entry form.

Production use

  • Use this chapter as the reference shape for all later tutorial examples.
  • Keep code blocks short enough for parser diagnostics to map to one line family.
  • Prefer one canonical form over several equivalent-looking variants.

What to avoid

  • Do not teach syntax through disconnected fragments.
  • Do not mix parser errors with type or domain errors in the first example.
  • Do not add advanced compiler constructs before block shape is stable.

Global explanation

Essential syntax is best taught as structure. The reader should see where declarations live, where statements live, and how a block closes with an explicit result.

Invalid case

proc broken(x: int) -> int
  give x
}

This invalid case is intentionally small. It exists to isolate the contract failure that the chapter is trying to teach.

Common pitfalls

  • Teaching surface tokens without explaining block shape.
  • Using syntax pages to comment every line instead of naming the pattern.
  • Confusing grammar shape with later semantic checks.

Short exercise

Add one extra branch and one extra local binding while preserving the same readable block structure.

Summary in 5 points

  1. Syntax is about shape before detail.
  2. A valid block is the smallest useful teaching unit.
  3. Statements and declarations belong to different layers.
  4. Invalid examples should isolate shape errors.
  5. The reader should leave able to recognize a healthy block instantly.

See also

Next best action

Extend the coherent example by one small, justified step and keep the same contract visible from input to output.

Chapter deep dive

04-syntax shows how valid code is shaped before semantics get deeper. The chapter is written for a reader learning to recognize well-formed Vitte at a glance.

The practical boundary is: declaration, block, branch, and explicit result. Keep that boundary in view while reading the example, the invalid case, and the exercise.

Role in the learning path

Syntax pages become noisy when they enumerate tokens without showing how a complete block is supposed to look.

One small block shows declarations, expressions, and returns in a single readable flow.

This chapter helps the reader recognize valid Vitte shapes quickly.

Profile-specific deep dive

Block shape

  • Top-level declarations establish the module before executable code starts.
  • Procedure bodies should make local bindings, branches, and final `give` easy to scan.
  • Closing braces are part of the readable contract because they define scope.

Statement layer

  • `let`, `set`, `if`, `for`, `match`, and `give` belong to different reading roles.
  • A syntax chapter should teach placement before advanced meaning.
  • The malformed example should fail because the shape is incomplete.

Reading the valid example

  1. space demo/syntax: names the ownership boundary before any behavior appears.
  2. proc compute(x: int, y: int) -> int {: states the callable contract: inputs first, result shape last.
  3. let sum: int = x + y: keeps an intermediate decision visible for review.
  4. if sum < 0 { give 0 }: guards a failure or edge case before the nominal result.
  5. give sum: ends the local path with an explicit result.
  6. }: supports the chapter contract without adding hidden behavior.
  7. proc main(args: list[string]) -> int {: states the callable contract: inputs first, result shape last.
  8. give compute(1, 2): ends the local path with an explicit result.
  9. }: supports the chapter contract without adding hidden behavior.
  10. export *: supports the chapter contract without adding hidden behavior.

Lesson from the invalid example

  1. proc broken(x: int) -> int: this line helps isolate the failure because it states the callable contract: inputs first, result shape last.
  2. give x: this line helps isolate the failure because it ends the local path with an explicit result.
  3. }: this line helps isolate the failure because it supports the chapter contract without adding hidden behavior.

Engineering decisions to preserve

  • Name the boundary before changing code: Syntax is about shape before detail.
  • Keep the smallest example executable: A valid block is the smallest useful teaching unit.
  • Make the invalid path explain one failure only: Statements and declarations belong to different layers.
  • Prefer a visible contract over an implied convention: Invalid examples should isolate shape errors.
  • Leave a review anchor that another maintainer can verify: The reader should leave able to recognize a healthy block instantly.

Context-specific review criteria

  • The page makes the declaration, block, branch, and explicit result boundary visible before the first code block.
  • The intended reader, a reader learning to recognize well-formed Vitte at a glance, can follow the valid example through named contracts instead of memorized tokens.
  • The invalid example fails for the same reason the prose discusses.
  • The exercise extends the same contract instead of introducing an unrelated concept.
  • The next chapter can reuse the vocabulary introduced here without redefining it.
  • The chapter stays specific enough that its title materially changes the meaning of the page.
  • Every warning connects to a concrete code shape.
  • The summary leaves one durable engineering rule behind.

Contract matrix

ConcernChapter ruleEvidence to keep
OwnershipCode belongs behind the boundary named by the chapter.The chapter keeps ownership visible through declaration, block, branch, and explicit result.
Input contractThe procedure receives a shape that is named before branching.The valid example names the accepted shape before branching.
Nominal pathThe clean path remains readable without hidden state.The successful result can be found without reading hidden state.
Failure pathThe invalid case isolates one failure reason.The broken example has one main reason to fail.
NamingNames explain the domain rather than only the mechanism.Names remain tied to the chapter goal.
TypesTypes remove ambiguity from values and results.Fields and return values carry domain meaning.
Control flowBranches stay traceable from guard to result.Guards appear before the result they protect.
Module boundaryThe public surface stays smaller than implementation detail.The public surface remains smaller than the implementation detail.
Diagnostic valueThe failure path points back to the exact contract.The invalid example points back to the exact contract.
Test valueRegression evidence covers one passing path and one failing path.One passing case and one failing case cover the lesson.
Refactor valueImplementation cleanup preserves the result shape.The result shape stays stable during local cleanup.
Publication valueThe chapter leaves one concrete engineering rule.The chapter leaves one concrete engineering rule.

Rewrite path for this chapter

  1. Rewrite the opening paragraph so it names declaration, block, branch, and explicit result before naming syntax.
  2. Keep the valid example small enough that the full contract fits on screen.
  3. Move any broad claim back to a specific line in the example.
  4. Preserve one invalid case that fails for the chapter's main reason.
  5. Add one sentence explaining why the invalid case is not a random error.
  6. Make every pitfall actionable by naming the code shape it damages.
  7. Keep the exercise inside the same domain as the example.
  8. Avoid introducing a second unrelated project just to show variety.
  9. Use the summary to restate the chapter rule, not the table of contents.
  10. Check that the next chapter can build on this vocabulary.
  11. Remove any sentence that would still be true in every other chapter.
  12. Keep the last action small, local, and testable.

Diagnostic anchors

  • The first inspected line is the one that declares the chapter's main contract.
  • The central type, field, procedure, or branch carries the chapter's main idea.
  • The invalid example includes a sentence-level explanation of its failure.
  • Refactors preserve the detail that would otherwise mislead a future reader.
  • The behavior that must stay stable is named before implementation changes begin.
  • Vague names are replaced before they become review friction.
  • Regression coverage protects the chapter's main contract.
  • Implementation details stay out of public API unless the chapter explicitly teaches that surface.
  • Beginner-facing diagnostics point to the contract, not to a random syntax detail.
  • The next chapter can assume one clearly named concept from this page.

When extending this chapter

  • Extend toward a reader learning to recognize well-formed Vitte at a glance, not toward a broader catalog of features.
  • Add a second example only if it sharpens the same contract.
  • Prefer a small variant over a new subsystem.
  • Keep prose close to code; every abstract claim should point to a visible shape.
  • Do not hide a new concept in the exercise.
  • If a paragraph explains policy, add the concrete code boundary it protects.
  • If a paragraph explains syntax, add the semantic reason the syntax matters.
  • If a paragraph explains architecture, identify the owner of each boundary.
  • If a paragraph explains failure, keep the failing line close to the explanation.
  • Stop expanding when the chapter has one complete, testable lesson.

Failure modes to avoid

  • Teaching surface tokens without explaining block shape.
  • Using syntax pages to comment every line instead of naming the pattern.
  • Confusing grammar shape with later semantic checks.

Practice scenario

Start from the coherent example in 04-syntax. Change one identifier, one guard, and one returned value. After each change, write down whether the public contract is still the same contract or a new one.

If the contract changed, update the type or result shape first. If only the implementation changed, keep the external name stable and add one regression note explaining what should not change again.

Before moving on

  • You can state the chapter role: shows how valid code is shaped before semantics get deeper.
  • You can point to the main boundary: declaration, block, branch, and explicit result.
  • You can connect the invalid case to the problem statement: Syntax pages become noisy when they enumerate tokens without showing how a complete block is supposed to look.
  • You can perform the exercise: Add one extra branch and one extra local binding while preserving the same readable block structure.