fix: parser newline handling in lists and stdlib exports
- Fix parse_list_expr to skip newlines between list elements - Add `pub` keyword to all exported functions in stdlib/html.lux - Change List.foldl to List.fold (matching built-in name) - Update weaknesses document with fixed issues The module import system now works correctly. This enables: - import stdlib/html to work as expected - html.div(), html.render() etc. to be accessible - Multi-line list expressions in Lux source files Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2266,12 +2266,15 @@ impl Parser {
|
|||||||
fn parse_list_expr(&mut self) -> Result<Expr, ParseError> {
|
fn parse_list_expr(&mut self) -> Result<Expr, ParseError> {
|
||||||
let start = self.current_span();
|
let start = self.current_span();
|
||||||
self.expect(TokenKind::LBracket)?;
|
self.expect(TokenKind::LBracket)?;
|
||||||
|
self.skip_newlines();
|
||||||
|
|
||||||
let mut elements = Vec::new();
|
let mut elements = Vec::new();
|
||||||
while !self.check(TokenKind::RBracket) {
|
while !self.check(TokenKind::RBracket) {
|
||||||
elements.push(self.parse_expr()?);
|
elements.push(self.parse_expr()?);
|
||||||
|
self.skip_newlines();
|
||||||
if !self.check(TokenKind::RBracket) {
|
if !self.check(TokenKind::RBracket) {
|
||||||
self.expect(TokenKind::Comma)?;
|
self.expect(TokenKind::Comma)?;
|
||||||
|
self.skip_newlines();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
162
stdlib/html.lux
162
stdlib/html.lux
@@ -11,13 +11,13 @@
|
|||||||
|
|
||||||
// Html type represents a DOM structure
|
// Html type represents a DOM structure
|
||||||
// Parameterized by Msg - the type of messages emitted by event handlers
|
// Parameterized by Msg - the type of messages emitted by event handlers
|
||||||
type Html<M> =
|
pub type Html<M> =
|
||||||
| Element(String, List<Attr<M>>, List<Html<M>>)
|
| Element(String, List<Attr<M>>, List<Html<M>>)
|
||||||
| Text(String)
|
| Text(String)
|
||||||
| Empty
|
| Empty
|
||||||
|
|
||||||
// Attributes that can be applied to elements
|
// Attributes that can be applied to elements
|
||||||
type Attr<M> =
|
pub type Attr<M> =
|
||||||
| Class(String)
|
| Class(String)
|
||||||
| Id(String)
|
| Id(String)
|
||||||
| Style(String, String)
|
| Style(String, String)
|
||||||
@@ -46,243 +46,243 @@ type Attr<M> =
|
|||||||
// Element builders - Container elements
|
// Element builders - Container elements
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
fn div<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn div<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("div", attrs, children)
|
Element("div", attrs, children)
|
||||||
|
|
||||||
fn span<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn span<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("span", attrs, children)
|
Element("span", attrs, children)
|
||||||
|
|
||||||
fn section<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn section<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("section", attrs, children)
|
Element("section", attrs, children)
|
||||||
|
|
||||||
fn article<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn article<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("article", attrs, children)
|
Element("article", attrs, children)
|
||||||
|
|
||||||
fn header<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn header<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("header", attrs, children)
|
Element("header", attrs, children)
|
||||||
|
|
||||||
fn footer<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn footer<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("footer", attrs, children)
|
Element("footer", attrs, children)
|
||||||
|
|
||||||
fn nav<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn nav<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("nav", attrs, children)
|
Element("nav", attrs, children)
|
||||||
|
|
||||||
fn main<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn main<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("main", attrs, children)
|
Element("main", attrs, children)
|
||||||
|
|
||||||
fn aside<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn aside<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("aside", attrs, children)
|
Element("aside", attrs, children)
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Element builders - Text elements
|
// Element builders - Text elements
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
fn h1<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn h1<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("h1", attrs, children)
|
Element("h1", attrs, children)
|
||||||
|
|
||||||
fn h2<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn h2<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("h2", attrs, children)
|
Element("h2", attrs, children)
|
||||||
|
|
||||||
fn h3<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn h3<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("h3", attrs, children)
|
Element("h3", attrs, children)
|
||||||
|
|
||||||
fn h4<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn h4<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("h4", attrs, children)
|
Element("h4", attrs, children)
|
||||||
|
|
||||||
fn h5<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn h5<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("h5", attrs, children)
|
Element("h5", attrs, children)
|
||||||
|
|
||||||
fn h6<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn h6<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("h6", attrs, children)
|
Element("h6", attrs, children)
|
||||||
|
|
||||||
fn p<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn p<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("p", attrs, children)
|
Element("p", attrs, children)
|
||||||
|
|
||||||
fn pre<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn pre<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("pre", attrs, children)
|
Element("pre", attrs, children)
|
||||||
|
|
||||||
fn code<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn code<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("code", attrs, children)
|
Element("code", attrs, children)
|
||||||
|
|
||||||
fn blockquote<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn blockquote<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("blockquote", attrs, children)
|
Element("blockquote", attrs, children)
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Element builders - Inline elements
|
// Element builders - Inline elements
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
fn a<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn a<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("a", attrs, children)
|
Element("a", attrs, children)
|
||||||
|
|
||||||
fn strong<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn strong<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("strong", attrs, children)
|
Element("strong", attrs, children)
|
||||||
|
|
||||||
fn em<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn em<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("em", attrs, children)
|
Element("em", attrs, children)
|
||||||
|
|
||||||
fn small<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn small<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("small", attrs, children)
|
Element("small", attrs, children)
|
||||||
|
|
||||||
fn br<M>(): Html<M> =
|
pub fn br<M>(): Html<M> =
|
||||||
Element("br", [], [])
|
Element("br", [], [])
|
||||||
|
|
||||||
fn hr<M>(): Html<M> =
|
pub fn hr<M>(): Html<M> =
|
||||||
Element("hr", [], [])
|
Element("hr", [], [])
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Element builders - Lists
|
// Element builders - Lists
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
fn ul<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn ul<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("ul", attrs, children)
|
Element("ul", attrs, children)
|
||||||
|
|
||||||
fn ol<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn ol<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("ol", attrs, children)
|
Element("ol", attrs, children)
|
||||||
|
|
||||||
fn li<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn li<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("li", attrs, children)
|
Element("li", attrs, children)
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Element builders - Forms
|
// Element builders - Forms
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
fn form<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn form<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("form", attrs, children)
|
Element("form", attrs, children)
|
||||||
|
|
||||||
fn input<M>(attrs: List<Attr<M>>): Html<M> =
|
pub fn input<M>(attrs: List<Attr<M>>): Html<M> =
|
||||||
Element("input", attrs, [])
|
Element("input", attrs, [])
|
||||||
|
|
||||||
fn textarea<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn textarea<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("textarea", attrs, children)
|
Element("textarea", attrs, children)
|
||||||
|
|
||||||
fn button<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn button<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("button", attrs, children)
|
Element("button", attrs, children)
|
||||||
|
|
||||||
fn label<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn label<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("label", attrs, children)
|
Element("label", attrs, children)
|
||||||
|
|
||||||
fn select<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn select<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("select", attrs, children)
|
Element("select", attrs, children)
|
||||||
|
|
||||||
fn option<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn option<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("option", attrs, children)
|
Element("option", attrs, children)
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Element builders - Media
|
// Element builders - Media
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
fn img<M>(attrs: List<Attr<M>>): Html<M> =
|
pub fn img<M>(attrs: List<Attr<M>>): Html<M> =
|
||||||
Element("img", attrs, [])
|
Element("img", attrs, [])
|
||||||
|
|
||||||
fn video<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn video<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("video", attrs, children)
|
Element("video", attrs, children)
|
||||||
|
|
||||||
fn audio<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn audio<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("audio", attrs, children)
|
Element("audio", attrs, children)
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Element builders - Tables
|
// Element builders - Tables
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
fn table<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn table<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("table", attrs, children)
|
Element("table", attrs, children)
|
||||||
|
|
||||||
fn thead<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn thead<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("thead", attrs, children)
|
Element("thead", attrs, children)
|
||||||
|
|
||||||
fn tbody<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn tbody<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("tbody", attrs, children)
|
Element("tbody", attrs, children)
|
||||||
|
|
||||||
fn tr<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn tr<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("tr", attrs, children)
|
Element("tr", attrs, children)
|
||||||
|
|
||||||
fn th<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn th<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("th", attrs, children)
|
Element("th", attrs, children)
|
||||||
|
|
||||||
fn td<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
pub fn td<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
|
||||||
Element("td", attrs, children)
|
Element("td", attrs, children)
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Text and empty nodes
|
// Text and empty nodes
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
fn text<M>(content: String): Html<M> =
|
pub fn text<M>(content: String): Html<M> =
|
||||||
Text(content)
|
Text(content)
|
||||||
|
|
||||||
fn empty<M>(): Html<M> =
|
pub fn empty<M>(): Html<M> =
|
||||||
Empty
|
Empty
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Attribute helpers
|
// Attribute helpers
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
fn class<M>(name: String): Attr<M> =
|
pub fn class<M>(name: String): Attr<M> =
|
||||||
Class(name)
|
Class(name)
|
||||||
|
|
||||||
fn id<M>(name: String): Attr<M> =
|
pub fn id<M>(name: String): Attr<M> =
|
||||||
Id(name)
|
Id(name)
|
||||||
|
|
||||||
fn style<M>(property: String, value: String): Attr<M> =
|
pub fn style<M>(property: String, value: String): Attr<M> =
|
||||||
Style(property, value)
|
Style(property, value)
|
||||||
|
|
||||||
fn href<M>(url: String): Attr<M> =
|
pub fn href<M>(url: String): Attr<M> =
|
||||||
Href(url)
|
Href(url)
|
||||||
|
|
||||||
fn src<M>(url: String): Attr<M> =
|
pub fn src<M>(url: String): Attr<M> =
|
||||||
Src(url)
|
Src(url)
|
||||||
|
|
||||||
fn alt<M>(description: String): Attr<M> =
|
pub fn alt<M>(description: String): Attr<M> =
|
||||||
Alt(description)
|
Alt(description)
|
||||||
|
|
||||||
fn inputType<M>(t: String): Attr<M> =
|
pub fn inputType<M>(t: String): Attr<M> =
|
||||||
Type(t)
|
Type(t)
|
||||||
|
|
||||||
fn value<M>(v: String): Attr<M> =
|
pub fn value<M>(v: String): Attr<M> =
|
||||||
Value(v)
|
Value(v)
|
||||||
|
|
||||||
fn placeholder<M>(p: String): Attr<M> =
|
pub fn placeholder<M>(p: String): Attr<M> =
|
||||||
Placeholder(p)
|
Placeholder(p)
|
||||||
|
|
||||||
fn disabled<M>(d: Bool): Attr<M> =
|
pub fn disabled<M>(d: Bool): Attr<M> =
|
||||||
Disabled(d)
|
Disabled(d)
|
||||||
|
|
||||||
fn checked<M>(c: Bool): Attr<M> =
|
pub fn checked<M>(c: Bool): Attr<M> =
|
||||||
Checked(c)
|
Checked(c)
|
||||||
|
|
||||||
fn name<M>(n: String): Attr<M> =
|
pub fn name<M>(n: String): Attr<M> =
|
||||||
Name(n)
|
Name(n)
|
||||||
|
|
||||||
fn onClick<M>(msg: M): Attr<M> =
|
pub fn onClick<M>(msg: M): Attr<M> =
|
||||||
OnClick(msg)
|
OnClick(msg)
|
||||||
|
|
||||||
fn onInput<M>(h: fn(String): M): Attr<M> =
|
pub fn onInput<M>(h: fn(String): M): Attr<M> =
|
||||||
OnInput(h)
|
OnInput(h)
|
||||||
|
|
||||||
fn onSubmit<M>(msg: M): Attr<M> =
|
pub fn onSubmit<M>(msg: M): Attr<M> =
|
||||||
OnSubmit(msg)
|
OnSubmit(msg)
|
||||||
|
|
||||||
fn onChange<M>(h: fn(String): M): Attr<M> =
|
pub fn onChange<M>(h: fn(String): M): Attr<M> =
|
||||||
OnChange(h)
|
OnChange(h)
|
||||||
|
|
||||||
fn onMouseEnter<M>(msg: M): Attr<M> =
|
pub fn onMouseEnter<M>(msg: M): Attr<M> =
|
||||||
OnMouseEnter(msg)
|
OnMouseEnter(msg)
|
||||||
|
|
||||||
fn onMouseLeave<M>(msg: M): Attr<M> =
|
pub fn onMouseLeave<M>(msg: M): Attr<M> =
|
||||||
OnMouseLeave(msg)
|
OnMouseLeave(msg)
|
||||||
|
|
||||||
fn onFocus<M>(msg: M): Attr<M> =
|
pub fn onFocus<M>(msg: M): Attr<M> =
|
||||||
OnFocus(msg)
|
OnFocus(msg)
|
||||||
|
|
||||||
fn onBlur<M>(msg: M): Attr<M> =
|
pub fn onBlur<M>(msg: M): Attr<M> =
|
||||||
OnBlur(msg)
|
OnBlur(msg)
|
||||||
|
|
||||||
fn onKeyDown<M>(h: fn(String): M): Attr<M> =
|
pub fn onKeyDown<M>(h: fn(String): M): Attr<M> =
|
||||||
OnKeyDown(h)
|
OnKeyDown(h)
|
||||||
|
|
||||||
fn onKeyUp<M>(h: fn(String): M): Attr<M> =
|
pub fn onKeyUp<M>(h: fn(String): M): Attr<M> =
|
||||||
OnKeyUp(h)
|
OnKeyUp(h)
|
||||||
|
|
||||||
fn data<M>(name: String, value: String): Attr<M> =
|
pub fn data<M>(name: String, value: String): Attr<M> =
|
||||||
DataAttr(name, value)
|
DataAttr(name, value)
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -290,11 +290,11 @@ fn data<M>(name: String, value: String): Attr<M> =
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
// Conditionally include an element
|
// Conditionally include an element
|
||||||
fn when<M>(condition: Bool, element: Html<M>): Html<M> =
|
pub fn when<M>(condition: Bool, element: Html<M>): Html<M> =
|
||||||
if condition then element else Empty
|
if condition then element else Empty
|
||||||
|
|
||||||
// Conditionally apply attributes
|
// Conditionally apply attributes
|
||||||
fn attrIf<M>(condition: Bool, attr: Attr<M>): List<Attr<M>> =
|
pub fn attrIf<M>(condition: Bool, attr: Attr<M>): List<Attr<M>> =
|
||||||
if condition then [attr] else []
|
if condition then [attr] else []
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -302,7 +302,7 @@ fn attrIf<M>(condition: Bool, attr: Attr<M>): List<Attr<M>> =
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
// Render an attribute to a string
|
// Render an attribute to a string
|
||||||
fn renderAttr<M>(attr: Attr<M>): String =
|
pub fn renderAttr<M>(attr: Attr<M>): String =
|
||||||
match attr {
|
match attr {
|
||||||
Class(name) => " class=\"" + name + "\"",
|
Class(name) => " class=\"" + name + "\"",
|
||||||
Id(name) => " id=\"" + name + "\"",
|
Id(name) => " id=\"" + name + "\"",
|
||||||
@@ -333,24 +333,24 @@ fn renderAttr<M>(attr: Attr<M>): String =
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Render attributes list to string
|
// Render attributes list to string
|
||||||
fn renderAttrs<M>(attrs: List<Attr<M>>): String =
|
pub fn renderAttrs<M>(attrs: List<Attr<M>>): String =
|
||||||
List.foldl(attrs, "", fn(acc, attr) => acc + renderAttr(attr))
|
List.fold(attrs, "", fn(acc, attr) => acc + renderAttr(attr))
|
||||||
|
|
||||||
// Self-closing tags
|
// Self-closing tags
|
||||||
fn isSelfClosing(tag: String): Bool =
|
pub fn isSelfClosing(tag: String): Bool =
|
||||||
tag == "br" || tag == "hr" || tag == "img" || tag == "input" ||
|
tag == "br" || tag == "hr" || tag == "img" || tag == "input" ||
|
||||||
tag == "meta" || tag == "link" || tag == "area" || tag == "base" ||
|
tag == "meta" || tag == "link" || tag == "area" || tag == "base" ||
|
||||||
tag == "col" || tag == "embed" || tag == "source" || tag == "track" || tag == "wbr"
|
tag == "col" || tag == "embed" || tag == "source" || tag == "track" || tag == "wbr"
|
||||||
|
|
||||||
// Render Html to string
|
// Render Html to string
|
||||||
fn render<M>(html: Html<M>): String =
|
pub fn render<M>(html: Html<M>): String =
|
||||||
match html {
|
match html {
|
||||||
Element(tag, attrs, children) => {
|
Element(tag, attrs, children) => {
|
||||||
let attrStr = renderAttrs(attrs)
|
let attrStr = renderAttrs(attrs)
|
||||||
if isSelfClosing(tag) then
|
if isSelfClosing(tag) then
|
||||||
"<" + tag + attrStr + " />"
|
"<" + tag + attrStr + " />"
|
||||||
else {
|
else {
|
||||||
let childrenStr = List.foldl(children, "", fn(acc, child) => acc + render(child))
|
let childrenStr = List.fold(children, "", fn(acc, child) => acc + render(child))
|
||||||
"<" + tag + attrStr + ">" + childrenStr + "</" + tag + ">"
|
"<" + tag + attrStr + ">" + childrenStr + "</" + tag + ">"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -359,7 +359,7 @@ fn render<M>(html: Html<M>): String =
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Escape HTML special characters
|
// Escape HTML special characters
|
||||||
fn escapeHtml(s: String): String = {
|
pub fn escapeHtml(s: String): String = {
|
||||||
// Simple replacement - a full implementation would handle all entities
|
// Simple replacement - a full implementation would handle all entities
|
||||||
let s1 = String.replace(s, "&", "&")
|
let s1 = String.replace(s, "&", "&")
|
||||||
let s2 = String.replace(s1, "<", "<")
|
let s2 = String.replace(s1, "<", "<")
|
||||||
@@ -369,7 +369,7 @@ fn escapeHtml(s: String): String = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Render a full HTML document
|
// Render a full HTML document
|
||||||
fn document(title: String, headExtra: List<Html<M>>, bodyContent: List<Html<M>>): String = {
|
pub fn document(title: String, headExtra: List<Html<M>>, bodyContent: List<Html<M>>): String = {
|
||||||
let headElements = List.concat([
|
let headElements = List.concat([
|
||||||
[Element("meta", [DataAttr("charset", "UTF-8")], [])],
|
[Element("meta", [DataAttr("charset", "UTF-8")], [])],
|
||||||
[Element("meta", [Name("viewport"), Value("width=device-width, initial-scale=1.0")], [])],
|
[Element("meta", [Name("viewport"), Value("width=device-width, initial-scale=1.0")], [])],
|
||||||
|
|||||||
@@ -2,49 +2,62 @@
|
|||||||
|
|
||||||
This document tracks issues and limitations discovered while building the Lux website in Lux.
|
This document tracks issues and limitations discovered while building the Lux website in Lux.
|
||||||
|
|
||||||
## Critical Issues
|
## Fixed Issues
|
||||||
|
|
||||||
### 1. Module Import System Not Working
|
### 1. Module Import System Not Working (FIXED)
|
||||||
|
|
||||||
**Description:** The `import` statement doesn't appear to work for importing standard library modules.
|
**Description:** The `import` statement wasn't working for importing standard library modules.
|
||||||
|
|
||||||
**Example:**
|
**Root Cause:** Two issues were found:
|
||||||
```lux
|
1. Parser didn't skip newlines inside list expressions, causing parse errors in multi-line lists
|
||||||
import html // Doesn't make html functions available
|
2. Functions in stdlib modules weren't marked as `pub` (public), so they weren't exported
|
||||||
```
|
|
||||||
|
|
||||||
**Workaround:** Functions must be defined in the same file or copied.
|
**Fix:**
|
||||||
|
1. Added `skip_newlines()` calls to `parse_list_expr()` in parser.rs
|
||||||
|
2. Added `pub` keyword to all exported functions in stdlib/html.lux
|
||||||
|
|
||||||
**Status:** Needs investigation
|
**Status:** FIXED
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 2. Parse Error in html.lux (Line 196-197)
|
### 2. Parse Error in html.lux (FIXED)
|
||||||
|
|
||||||
**Description:** When trying to load files that import the html module, there's a parse error.
|
**Description:** When trying to load files that import the html module, there was a parse error at line 196-197.
|
||||||
|
|
||||||
**Error Message:**
|
**Error Message:**
|
||||||
```
|
```
|
||||||
Module error: Module error in '<main>': Parse error: Parse error at 196-197: Unexpected token: \n
|
Module error: Module error in '<main>': Parse error: Parse error at 196-197: Unexpected token: \n
|
||||||
```
|
```
|
||||||
|
|
||||||
**Status:** Needs investigation
|
**Root Cause:** The parser's `parse_list_expr()` function didn't handle newlines between list elements.
|
||||||
|
|
||||||
|
**Fix:** Added `skip_newlines()` calls after `[`, after each element, and after commas in list expressions.
|
||||||
|
|
||||||
|
**Status:** FIXED
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. List.foldl Renamed to List.fold (FIXED)
|
||||||
|
|
||||||
|
**Description:** The html.lux file used `List.foldl` but the built-in List module exports `List.fold`.
|
||||||
|
|
||||||
|
**Fix:** Changed `List.foldl` to `List.fold` in stdlib/html.lux.
|
||||||
|
|
||||||
|
**Status:** FIXED
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Minor Issues
|
## Minor Issues
|
||||||
|
|
||||||
### 3. String.replace May Not Exist
|
### 4. String.replace Verified Working
|
||||||
|
|
||||||
**Description:** The `escapeHtml` function in html.lux uses `String.replace`, but this function may not be implemented.
|
**Description:** The `escapeHtml` function in html.lux uses `String.replace`.
|
||||||
|
|
||||||
**Workaround:** Implement character-by-character escaping.
|
**Status:** VERIFIED WORKING - String.replace is implemented in the interpreter.
|
||||||
|
|
||||||
**Status:** Needs verification
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 4. FileSystem Effect Not Fully Implemented
|
### 5. FileSystem Effect Not Fully Implemented
|
||||||
|
|
||||||
**Description:** For static site generation, we need `FileSystem.mkdir`, `FileSystem.write`, `FileSystem.copy` operations. These may not be fully implemented.
|
**Description:** For static site generation, we need `FileSystem.mkdir`, `FileSystem.write`, `FileSystem.copy` operations. These may not be fully implemented.
|
||||||
|
|
||||||
@@ -54,17 +67,17 @@ Module error: Module error in '<main>': Parse error: Parse error at 196-197: Une
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 5. List.concat May Have Issues
|
### 6. List.concat Verified Working
|
||||||
|
|
||||||
**Description:** The `List.concat` function used in html.lux document generation may not handle nested lists correctly.
|
**Description:** The `List.concat` function is used in html.lux document generation.
|
||||||
|
|
||||||
**Status:** Needs verification
|
**Status:** VERIFIED WORKING - List.concat is implemented in the interpreter.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Feature Gaps
|
## Feature Gaps
|
||||||
|
|
||||||
### 6. No Built-in Static Site Generation
|
### 7. No Built-in Static Site Generation
|
||||||
|
|
||||||
**Description:** There's no built-in way to generate static HTML files from Lux. A static site generator effect or module would be helpful.
|
**Description:** There's no built-in way to generate static HTML files from Lux. A static site generator effect or module would be helpful.
|
||||||
|
|
||||||
@@ -76,7 +89,7 @@ Module error: Module error in '<main>': Parse error: Parse error at 196-197: Une
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 7. No Template String Support
|
### 8. No Template String Support
|
||||||
|
|
||||||
**Description:** Multi-line strings and template literals (like JavaScript's backticks) would make HTML generation much easier.
|
**Description:** Multi-line strings and template literals (like JavaScript's backticks) would make HTML generation much easier.
|
||||||
|
|
||||||
@@ -94,7 +107,7 @@ let html = `<div class="${className}">${content}</div>`
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 8. No Markdown Parser
|
### 9. No Markdown Parser
|
||||||
|
|
||||||
**Description:** A built-in Markdown parser would be valuable for documentation sites.
|
**Description:** A built-in Markdown parser would be valuable for documentation sites.
|
||||||
|
|
||||||
@@ -112,6 +125,8 @@ These features work correctly and can be used for website generation:
|
|||||||
4. **Basic types** - `String`, `Int`, `Bool` work
|
4. **Basic types** - `String`, `Int`, `Bool` work
|
||||||
5. **Let bindings** - Variable assignment works
|
5. **Let bindings** - Variable assignment works
|
||||||
6. **Functions** - Function definitions work
|
6. **Functions** - Function definitions work
|
||||||
|
7. **Module imports** - Works with `import stdlib/module`
|
||||||
|
8. **Html module** - Fully functional for generating HTML strings
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -119,15 +134,14 @@ These features work correctly and can be used for website generation:
|
|||||||
|
|
||||||
### For Website MVP
|
### For Website MVP
|
||||||
|
|
||||||
Since the module system isn't working, the website should be:
|
The module system now works! The website can be:
|
||||||
1. **Hand-written HTML** (already done in `dist/index.html`)
|
1. **Generated from Lux** using the html module for HTML rendering
|
||||||
2. **CSS separate file** (already done in `static/style.css`)
|
2. **CSS separate file** (already done in `static/style.css`)
|
||||||
3. **Lux code examples** embedded as text in HTML
|
3. **Lux code examples** embedded as text in HTML
|
||||||
|
|
||||||
### For Future
|
### For Future
|
||||||
|
|
||||||
Once these issues are fixed, the website can be:
|
1. **Add FileSystem effect** for writing generated HTML to files
|
||||||
1. **Generated from Lux** using the components and pages modules
|
|
||||||
2. **Markdown-based documentation** parsed and rendered by Lux
|
2. **Markdown-based documentation** parsed and rendered by Lux
|
||||||
3. **Live playground** using WASM compilation
|
3. **Live playground** using WASM compilation
|
||||||
|
|
||||||
@@ -137,12 +151,15 @@ Once these issues are fixed, the website can be:
|
|||||||
|
|
||||||
| Feature | Status | Notes |
|
| Feature | Status | Notes |
|
||||||
|---------|--------|-------|
|
|---------|--------|-------|
|
||||||
| String concatenation | ✅ Works | `"<" + tag + ">"` |
|
| String concatenation | Works | `"<" + tag + ">"` |
|
||||||
| Conditionals | ✅ Works | `if x then y else z` |
|
| Conditionals | Works | `if x then y else z` |
|
||||||
| Console.print | ✅ Works | Basic output |
|
| Console.print | Works | Basic output |
|
||||||
| Module imports | ❌ Broken | Parse errors |
|
| Module imports | Works | `import stdlib/html` |
|
||||||
| Html module | ❌ Blocked | Depends on imports |
|
| Html module | Works | Full HTML generation |
|
||||||
| FileSystem | ❓ Unknown | Not tested |
|
| List.fold | Works | Fold over lists |
|
||||||
|
| List.concat | Works | Concatenate list of lists |
|
||||||
|
| String.replace | Works | String replacement |
|
||||||
|
| FileSystem | Unknown | Not tested |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -151,3 +168,6 @@ Once these issues are fixed, the website can be:
|
|||||||
| Date | Finding |
|
| Date | Finding |
|
||||||
|------|---------|
|
|------|---------|
|
||||||
| 2026-02-16 | Module import system not working, parse error at line 196-197 in html.lux |
|
| 2026-02-16 | Module import system not working, parse error at line 196-197 in html.lux |
|
||||||
|
| 2026-02-16 | Fixed: Parser newline handling in list expressions |
|
||||||
|
| 2026-02-16 | Fixed: Added `pub` to stdlib/html.lux exports |
|
||||||
|
| 2026-02-16 | Fixed: Changed List.foldl to List.fold |
|
||||||
|
|||||||
Reference in New Issue
Block a user