Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add code check #351

Merged
merged 3 commits into from
Dec 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions next/_ext/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import tempfile
import subprocess
from docutils.nodes import document, Node, NodeVisitor
from sphinx.application import Sphinx
from sphinx.util.typing import ExtensionMetadata
from sphinx.util import logging

logger = logging.getLogger(__name__)

def setup(app: Sphinx) -> ExtensionMetadata:
metadata = {
"version": "0.1.0",
"parallel_read_safe": True,
"parallel_write_safe": True,
}
try:
result = subprocess.run(["moonc", '-v'], capture_output=True, check=True)
except (FileNotFoundError, subprocess.CalledProcessError):
logger.warning("moonbit compiler is missing! No code check performed")
return metadata
logger.info(f"moonc version: {result.stdout.decode().strip()}")
app.connect("doctree-read", source_read_handler)
return metadata

class Visitor(NodeVisitor):
def visit_literal_block(self, node : Node):
if 'language' in node.attributes \
and (node.attributes['language'] == 'moonbit' or node.attributes['language'] == 'mbt') \
and 'classes' in node.attributes:
if node.attributes['classes'].count('expr') > 0:
# Check as expression
with tempfile.NamedTemporaryFile(suffix=".mbt") as temp_file:
temp_file.write("fn init {\n".encode())
temp_file.write("\n".join([" " + line for line in node.astext().splitlines()]).encode())
temp_file.write("\n}".encode())
temp_file.flush()
temp_file_path = temp_file.name

result = subprocess.run(["moonc", "compile", "-stop-after-parsing", temp_file_path], capture_output=True)
if result.returncode != 0:
logger.error(f"code check failed: {result.stderr.decode().strip()}")

elif node.attributes['classes'].count('top-level') > 0:
# Check as top-level
with tempfile.NamedTemporaryFile(suffix=".mbt") as temp_file:
temp_file.write(node.astext().encode())
temp_file.flush()
temp_file_path = temp_file.name

result = subprocess.run(["moonc", "compile", "-stop-after-parsing", temp_file_path], capture_output=True)
if result.returncode != 0:
logger.error(f"code check failed: {result.stderr.decode().strip()}", location=node)
def unknown_visit(self, _node):
return

def source_read_handler(_app : Sphinx, doctree: document):
doctree.walk(Visitor(doctree))
4 changes: 3 additions & 1 deletion next/_ext/indent.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ def __init__(self, s, _):
def __radd__(self, _):
return f"```\n{self.s}\n```"

i18n.indent = ModifiedIndent
i18n.indent = ModifiedIndent

def setup(_app): pass
4 changes: 2 additions & 2 deletions next/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from pathlib import Path
sys.path.append(str(Path("_ext").resolve()))

extensions = ['myst_parser', 'lexer', 'indent', 'sphinx_copybutton']
extensions = ['myst_parser', 'lexer', 'check', 'indent', 'sphinx_copybutton']

templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', ".env", '.venv', "README", 'sources']
Expand All @@ -27,7 +27,7 @@
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = 'sphinx_book_theme'
html_static_path = ['_static']
# html_static_path = ['_static']
html_theme_options = {
"repository_url": "https://github.com/moonbitlang/moonbit-docs/",
"path_to_docs": "next",
Expand Down
50 changes: 36 additions & 14 deletions next/language/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,18 @@ A MoonBit program consists of top-level definitions including:

MoonBit distinguishes between statements and expressions. In a function body, only the last clause should be an expression, which serves as a return value. For example:

```{literalinclude} /sources/language/src/functions/top.mbt
:language: moonbit
:start-after: start expression
:end-before: end expression
```{code-block} moonbit
:class: top-level
fn foo() -> Int {
let x = 1
x + 1
}

fn bar() -> Int {
let x = 1
//! x + 1
x + 2
}
```

Expressions include:
Expand Down Expand Up @@ -42,8 +50,18 @@ A variable can be declared as mutable or immutable using `let mut` or `let`, res

A constant can only be declared at top level and cannot be changed.

```{literalinclude} /sources/language/src/variable/top.mbt
:language: moonbit
```{code-block} moonbit
:class: top-level
let zero = 0

const ZERO = 0

fn main {
//! const ZERO = 0
let mut i = 10
i = 20
println(i + zero + ZERO)
}
```

## Naming conventions
Expand All @@ -64,20 +82,24 @@ There is a specialized function called `init` function. The `init` function is s
3. An `init` function can't be explicitly called or referred to by other functions.
Instead, all `init` functions will be implicitly called when initializing a package. Therefore, `init` functions should only consist of statements.

```{literalinclude} /sources/language/src/main/top.mbt
:language: moonbit
:start-after: start init
:end-before: end init
```{code-block} moonbit
:class: top-level
fn init {
let x = 1
println(x)
}
```

There is another specialized function called `main` function. The `main` function is the main entrance of the program, and it will be executed after the initialization stage.

Same as the `init` function, it has no parameter list nor return type.

```{literalinclude} /sources/language/src/main/top.mbt
:language: moonbit
:start-after: start main
:end-before: end main
```{code-block} moonbit
:class: top-level
fn main {
let x = 2
println(x)
}
```

The previous two code snippets will print the following at runtime:
Expand Down
Loading