Skip to content
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
8 changes: 0 additions & 8 deletions .github/workflows/extended_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,14 +256,6 @@ jobs:
cd modules/dasImgui && git diff --exit-code -- src/ \
|| (echo "ERROR: dasImgui generated files are out of date. Run './bin/daslang modules/dasImgui/bind/bind_imgui.das' locally and commit the result." && exit 1)

- name: "Dry-run imgui examples"
run: |
set -eux
for f in modules/dasImgui/example/*.das; do
echo "== compile-only: $f =="
$BIN/daslang -compile-only "$f"
done

- name: "Coverage"
if: matrix.target == 'linux'
run: |
Expand Down
20 changes: 10 additions & 10 deletions daslib/algorithm.das
Original file line number Diff line number Diff line change
Expand Up @@ -408,8 +408,8 @@ def erase_all(var arr; value) {

def fill(var a : array<auto(TT)>; value : TT const -&) {
//! Sets all elements of the array to the given value using clone.
for (i in range(length(a))) {
a[i] := value
for (e in a) {
e := value
}
}

Expand All @@ -419,8 +419,8 @@ def fill(var a; value) {
static_if (typeinfo stripped_typename(a[0]) != typeinfo stripped_typename(value)) {
concept_assert(false, "value type {typeinfo stripped_typename(value)} should be the same as array {typeinfo stripped_typename(a)} element type {typeinfo stripped_typename(a[0])}")
} else {
for (i in range(length(a))) {
a[i] := value
for (e in a) {
e := value
}
}
}
Expand Down Expand Up @@ -486,7 +486,7 @@ def rotate(var a; mid : int) {

def min_element(a : array<auto(TT)>) : int {
//! Returns the index of the minimum element in the array, or -1 if the array is empty.
if (length(a) == 0) return -1
if (empty(a)) return -1
var best = 0
for (i in range(1, length(a))) {
if (a[i] < a[best]) {
Expand All @@ -498,7 +498,7 @@ def min_element(a : array<auto(TT)>) : int {

def min_element(a : array<auto(TT)>; less : block<(a, b : TT const -&) : bool>) : int {
//! Returns the index of the minimum element according to the provided less function, or -1 if the array is empty.
if (length(a) == 0) return -1
if (empty(a)) return -1
var best = 0
for (i in range(1, length(a))) {
if (invoke(less, a[i], a[best])) {
Expand All @@ -510,7 +510,7 @@ def min_element(a : array<auto(TT)>; less : block<(a, b : TT const -&) : bool>)

def max_element(a : array<auto(TT)>) : int {
//! Returns the index of the maximum element in the array, or -1 if the array is empty.
if (length(a) == 0) return -1
if (empty(a)) return -1
var best = 0
for (i in range(1, length(a))) {
if (a[best] < a[i]) {
Expand All @@ -522,7 +522,7 @@ def max_element(a : array<auto(TT)>) : int {

def max_element(a : array<auto(TT)>; less : block<(a, b : TT const -&) : bool>) : int {
//! Returns the index of the maximum element according to the provided less function, or -1 if the array is empty.
if (length(a) == 0) return -1
if (empty(a)) return -1
var best = 0
for (i in range(1, length(a))) {
if (invoke(less, a[best], a[i])) {
Expand Down Expand Up @@ -561,11 +561,11 @@ def topological_sort(nodes : array<auto(Node)>) {
if (lnodes != 0) {
sorted |> reserve(lnodes)
var unsorted : array<Node> := nodes
while (length(unsorted) > 0) {
while (!empty(unsorted)) {
var removed = 0
var i = 0
while (i < length(unsorted)) {
if (length(unsorted[i].before) == 0) {
if (empty(unsorted[i].before)) {
var node <- unsorted[i]
unsorted |> erase(i)
for (other in unsorted) {
Expand Down
8 changes: 3 additions & 5 deletions daslib/aot_cpp.das
Original file line number Diff line number Diff line change
Expand Up @@ -441,11 +441,9 @@ def expectsLocalTemp(expr : ExprMakeLocal?) : bool {
if (!expr.makeFlags.doesNotNeedSp && expr.stackTop != 0u) {
if (expr is ExprMakeStruct) {
let mks = expr as ExprMakeStruct
if (mks.makeType.baseType == Type.tHandle &&
!mks.makeType.isRefType &&
mks.constructor == null) {
return false
}
if (mks.makeType.baseType == Type.tHandle
&& !mks.makeType.isRefType
&& mks.constructor == null) return false
}
return true
}
Expand Down
4 changes: 2 additions & 2 deletions daslib/decs.das
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ def public for_each_archetype_find(hash : ComponentHash; var erq : function<() :
[unsafe_operation]
def decs_array(atype : auto(TT); src : array<uint8>; capacity : int) {
//! Low level function returns temporary array of component given specific type of component.
assert(length(src) > 0)
assert(!empty(src))
static_if (typeinfo is_dim(atype)) {
var dest : array<TT[typeinfo dim(atype)] -const -& -#>
unsafe {
Expand Down Expand Up @@ -1218,7 +1218,7 @@ def private make_callbacks(var cv : ComponentValue; value : auto(TT)) {
var ssrc : array<TT[typeinfo dim(value)] -const -& -#>
let size = length(src) / stride
unsafe {
if (length(src) > 0) {
if (!empty(src)) {
_builtin_make_temp_array(ssrc, addr(src[0]), size)
}
}
Expand Down
12 changes: 6 additions & 6 deletions daslib/linq.das
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ def take(arr : array<auto(TT)>; var total : int) : array<TT -& -const> {
def take_inplace(var arr : array<auto(TT)>; var total : int) {
//! Keeps only the first `total` elements in an array in place
let len = length(arr)
let taking = (total < len) ? total : len
let taking = min(total, len)
arr.resize(taking)
}

Expand Down Expand Up @@ -1902,7 +1902,7 @@ def union_by_to_array(var srca, srcb : iterator<auto(TT)>; key : block<(arg : TT

def any(src : array<auto(TT)>) : bool {
//! Returns true if the array has at least one element
return length(src) != 0
return !empty(src)
}

def any(var src : iterator<auto(TT)>) : bool {
Expand Down Expand Up @@ -1961,7 +1961,7 @@ def all(src : array<auto(TT)>; predicate : block<(arg : TT -&) : bool>) : bool {

def none(src : array<auto(TT)>) : bool {
//! Returns true if the array has no elements
return length(src) == 0
return empty(src)
}

def none(var src : iterator<auto(TT)>) : bool {
Expand Down Expand Up @@ -2372,7 +2372,7 @@ def element_at_or_default(var src : iterator<auto(TT)>; index : int) : TT -const

def first(src : array<auto(TT)>) : TT -const -& {
//! Returns the first element of an array
panic("sequence contains no elements") if (length(src) == 0)
panic("sequence contains no elements") if (empty(src))
static_if (typeinfo can_copy(src[0])) {
return src[0]
} else {
Expand All @@ -2396,7 +2396,7 @@ def first(var src : iterator<auto(TT)>) : TT -const -& {

def first_or_default(src : array<auto(TT)>; defaultValue : TT -&) : TT -const -& {
//! Returns the first element of an array, or a default value if the array is empty
if (length(src) == 0) {
if (empty(src)) {
static_if (typeinfo can_copy(defaultValue)) {
return defaultValue
} else {
Expand Down Expand Up @@ -2745,7 +2745,7 @@ def private chunk_impl(var src; tt : auto(TT); size : int) : array<array<TT -con
buffer.emplace(chunk)
}
}
if (chunk.length() > 0) {
if (!empty(chunk)) {
buffer.emplace(chunk)
}
return <- buffer
Expand Down
138 changes: 138 additions & 0 deletions doc/source/_static/custom-patch.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/* ──────────────────────────────────────────────────────────────────
* Forge — additive refinements on top of custom.css.
*
* Drop next to custom.css and load AFTER it:
* html_css_files = ['custom.css', 'custom-patch.css']
*
* Covers gaps G1–G11 documented in SPHINX_AUDIT.md.
* ────────────────────────────────────────────────────────────────── */

/* G1 — bare links, no permanent underline */
.rst-content a, .rst-content a:visited {
text-decoration: none !important;
border-bottom: 1px dotted transparent !important;
transition: border-color 0.12s, color 0.12s;
}
.rst-content a:hover {
color: var(--fg) !important;
border-bottom-color: var(--fg) !important;
}

/* G2 — admonition title takes the kind color */
.rst-content .admonition .admonition-title { color: var(--blue) !important; }
.rst-content .admonition.warning .admonition-title,
.rst-content .admonition.attention .admonition-title,
.rst-content .admonition.caution .admonition-title { color: var(--amber) !important; }
.rst-content .admonition.error .admonition-title,
.rst-content .admonition.danger .admonition-title { color: var(--red) !important; }
.rst-content .admonition.tip .admonition-title,
.rst-content .admonition.hint .admonition-title { color: var(--green) !important; }

/* G3 — kill table row striping, swap solid grid for dashed rows */
.rst-content table.docutils,
.wy-table-responsive table {
border-left: none !important;
border-right: none !important;
border-top: 1px solid var(--rule) !important;
border-bottom: 1px solid var(--rule) !important;
}
.rst-content table.docutils tbody tr td,
.rst-content table.docutils tbody tr:nth-child(odd) td,
.wy-table-responsive table tbody tr td,
.wy-table-responsive table tbody tr:nth-child(odd) td {
background: transparent !important;
border: none !important;
border-bottom: 1px dashed var(--rule) !important;
}
.rst-content table.docutils thead th,
.wy-table-responsive table thead th {
background: transparent !important;
border: none !important;
border-bottom: 1px solid var(--rule) !important;
font-family: var(--font-mono) !important;
font-size: 11px !important;
letter-spacing: 1.2px !important;
text-transform: uppercase !important;
color: var(--fg-faint) !important;
text-align: left;
}

/* G4 — anchors don't disappear under the sticky nav */
html { scroll-padding-top: 80px; }
.rst-content h1, .rst-content h2, .rst-content h3,
.rst-content h4, .rst-content h5, .rst-content h6 {
scroll-margin-top: 80px;
}

/* G5 — headerlink ¶ becomes a subtle hover-only → */
.rst-content a.headerlink {
color: transparent !important;
background: transparent !important;
border-bottom: none !important;
margin-left: 10px;
font-size: 0 !important; /* hide the ¶ glyph */
transition: color 0.12s;
vertical-align: middle;
}
.rst-content a.headerlink::before {
content: '→';
font-family: var(--font-mono);
font-size: 14px;
color: inherit;
}
.rst-content h1:hover a.headerlink, .rst-content h1:focus-within a.headerlink,
.rst-content h2:hover a.headerlink, .rst-content h2:focus-within a.headerlink,
.rst-content h3:hover a.headerlink, .rst-content h3:focus-within a.headerlink,
.rst-content h4:hover a.headerlink, .rst-content h4:focus-within a.headerlink,
.rst-content h5:hover a.headerlink, .rst-content h5:focus-within a.headerlink,
.rst-content h6:hover a.headerlink, .rst-content h6:focus-within a.headerlink {
color: var(--fg-faint) !important;
}
.rst-content a.headerlink:hover,
.rst-content a.headerlink:focus-visible { color: var(--amber) !important; }

/* G6 — branded text selection */
::selection { background: rgba(232,161,58,0.28); color: var(--fg); }

/* G7 — kbd */
.rst-content kbd, kbd.kbd, kbd.docutils.literal {
font-family: var(--font-mono);
font-size: 11px;
background: var(--bg-2);
border: 1px solid var(--rule);
border-radius: 3px;
padding: 1px 6px;
color: var(--fg);
box-shadow: 0 1px 0 var(--rule);
}

/* G8 — list markers */
.rst-content ul > li::marker { color: var(--fg-faint); }
.rst-content ol > li::marker {
color: var(--amber);
font-family: var(--font-mono);
font-size: 0.9em;
}

/* G9 — narrower prose, keep code/tables wide.
* <p> is never used for code blocks or tables, so capping every <p> is safe.
* Cells (td/th) explicitly opt out so wide tabular data still spans full width. */
.rst-content p { max-width: 720px; }
.rst-content td p,
.rst-content th p { max-width: none; }

/* G10 — heading scale matches landing/artboard */
.rst-content h1 { font-size: 44px !important; line-height: 1.1 !important; letter-spacing: -0.02em !important; }
.rst-content h2 { font-size: 26px !important; line-height: 1.3 !important; letter-spacing: -0.015em !important; margin-top: 40px; }
.rst-content h3 { font-size: 20px !important; line-height: 1.4 !important; letter-spacing: -0.01em !important; margin-top: 28px; }

/* G11 — inner <pre> shouldn't redraw the rounded corner */
.rst-content div[class^="highlight"] pre {
border-radius: 0 !important;
border: none !important;
}

/* Fallback: any un-tokenized signature text still reads as dim grey. */
.rst-content dt.sig-object { color: var(--fg-dim); }
.rst-content dt.sig-object .sig-name,
.rst-content dt.sig-object .sig-name.descname { color: var(--amber) !important; }
2 changes: 1 addition & 1 deletion doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@

# Custom CSS — Forge token overlay on top of sphinx_rtd_theme.
# See doc/source/_static/custom.css for the retoken rules.
html_css_files = ['custom.css']
html_css_files = ['custom.css', 'custom-patch.css']

# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
Expand Down
60 changes: 57 additions & 3 deletions doc/source/daslang.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,49 @@
Comment, Keyword, Name, Number, Operator, Punctuation, String, Text, Token
)

# G13b — signature syntax highlighting. We reuse DaslangLexer (defined
# further down in this file) to tokenize each signature's arglist and
# return type, then emit Pygments-classed inline nodes. CSS rules in
# _static/custom.css of the form `.highlight .k`, `.highlight .kt`, etc.
# then color signatures the same way they color code blocks.
from pygments import lex as _pygments_lex
from pygments.token import STANDARD_TYPES as _PYG_STANDARD_TYPES


def _das_token_class(ttype):
"""Map a Pygments token type to its short HTML class ('k', 'kt', 'n', …).
Walks up the token hierarchy until a STANDARD_TYPES match is found."""
while ttype is not None:
if ttype in _PYG_STANDARD_TYPES:
return _PYG_STANDARD_TYPES[ttype]
ttype = ttype.parent
return ''


# Lazy singleton — DaslangLexer is cheap but no need to rebuild per call.
_DAS_LEXER_SINGLETON = None
def _das_lexer():
global _DAS_LEXER_SINGLETON
if _DAS_LEXER_SINGLETON is None:
_DAS_LEXER_SINGLETON = DaslangLexer()
return _DAS_LEXER_SINGLETON


def _append_highlighted(signode, text):
"""Tokenize `text` with DaslangLexer and append classed inline nodes
to `signode`. Each token is wrapped with both `highlight` and the
Pygments short class (e.g. `kt` for type, `k` for keyword), so the
existing `.highlight .kt` style rules apply without modification."""
if not text:
return
for ttype, value in _pygments_lex(text, _das_lexer()):
cls = _das_token_class(ttype)
classes = ['highlight']
if cls:
classes.append(cls)
signode += nodes.inline(value, value, classes=classes)


from sphinx import version_info

from sphinx import addnodes
Expand Down Expand Up @@ -130,11 +173,22 @@ def handle_signature(self, sig, signode):
if self.has_arguments:
if not arglist:
if not self.skip_empty_arguments:
signode += addnodes.desc_parameterlist()
# Empty () for callables with skip_empty_arguments=False
signode += addnodes.desc_sig_punctuation('(', '(')
signode += addnodes.desc_sig_punctuation(')', ')')
else:
_pseudo_parse_arglist(signode, arglist)
# G13b — tokenize the arglist with DaslangLexer so each
# token (type, name, operator, etc.) ends up in its own
# span with a Pygments class name. Wrap with explicit
# parens so CSS layout stays consistent with the pre-
# patch behavior.
signode += addnodes.desc_sig_punctuation('(', '(')
_append_highlighted(signode, arglist)
signode += addnodes.desc_sig_punctuation(')', ')')
if retType:
signode += addnodes.desc_type(retType, retType)
# retType retains its leading ':' from handle_signature's
# split, so we can hand it to the lexer as-is.
_append_highlighted(signode, retType)
return fullname, prefix

def add_target_and_index(self, name_obj, sig, signode):
Expand Down
Loading
Loading