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
56 changes: 13 additions & 43 deletions crates/plotnik-cli/src/commands/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use plotnik_lib::Colors;
use plotnik_lib::QueryBuilder;
use plotnik_lib::bytecode::{Module, dump};

use super::lang_resolver::{resolve_lang, resolve_lang_required, suggest_language};
use super::lang_resolver::require_lang;
use super::query_loader::load_query_source;

pub struct DumpArgs {
Expand Down Expand Up @@ -38,49 +38,19 @@ pub fn run(args: DumpArgs) {
}
};

// Resolve language (optional - enables linking)
let lang = if let Some(lang_name) = &args.lang {
match resolve_lang_required(lang_name) {
Ok(l) => Some(l),
Err(msg) => {
eprintln!("error: {}", msg);
if let Some(suggestion) = suggest_language(lang_name) {
eprintln!();
eprintln!("Did you mean '{}'?", suggestion);
}
eprintln!();
eprintln!("Run 'plotnik langs' for the full list.");
std::process::exit(1);
}
}
} else {
resolve_lang(None, args.query_path.as_deref())
};
let lang = require_lang(args.lang.as_deref(), args.query_path.as_deref(), "dump");

let bytecode = if let Some(lang) = lang {
let linked = query.link(&lang);
if !linked.is_valid() {
eprint!(
"{}",
linked
.diagnostics()
.render_colored(linked.source_map(), args.color)
);
std::process::exit(1);
}
linked.emit().expect("bytecode emission failed")
} else {
if !query.is_valid() {
eprint!(
"{}",
query
.diagnostics()
.render_colored(query.source_map(), args.color)
);
std::process::exit(1);
}
query.emit().expect("bytecode emission failed")
};
let linked = query.link(&lang);
if !linked.is_valid() {
eprint!(
"{}",
linked
.diagnostics()
.render_colored(linked.source_map(), args.color)
);
std::process::exit(1);
}
let bytecode = linked.emit().expect("bytecode emission failed");

let module = Module::load(&bytecode).expect("module loading failed");
let colors = Colors::new(args.color);
Expand Down
56 changes: 13 additions & 43 deletions crates/plotnik-cli/src/commands/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use plotnik_lib::QueryBuilder;
use plotnik_lib::bytecode::Module;
use plotnik_lib::typegen::typescript;

use super::lang_resolver::{resolve_lang, resolve_lang_required, suggest_language};
use super::lang_resolver::require_lang;
use super::query_loader::load_query_source;

pub struct InferArgs {
Expand Down Expand Up @@ -53,49 +53,19 @@ pub fn run(args: InferArgs) {
}
};

// Resolve language (optional - enables linking)
let lang = if let Some(lang_name) = &args.lang {
match resolve_lang_required(lang_name) {
Ok(l) => Some(l),
Err(msg) => {
eprintln!("error: {}", msg);
if let Some(suggestion) = suggest_language(lang_name) {
eprintln!();
eprintln!("Did you mean '{}'?", suggestion);
}
eprintln!();
eprintln!("Run 'plotnik langs' for the full list.");
std::process::exit(1);
}
}
} else {
resolve_lang(None, args.query_path.as_deref())
};
let lang = require_lang(args.lang.as_deref(), args.query_path.as_deref(), "infer");

let bytecode = if let Some(lang) = lang {
let linked = query.link(&lang);
if !linked.is_valid() {
eprint!(
"{}",
linked
.diagnostics()
.render_colored(linked.source_map(), args.color)
);
std::process::exit(1);
}
linked.emit().expect("bytecode emission failed")
} else {
if !query.is_valid() {
eprint!(
"{}",
query
.diagnostics()
.render_colored(query.source_map(), args.color)
);
std::process::exit(1);
}
query.emit().expect("bytecode emission failed")
};
let linked = query.link(&lang);
if !linked.is_valid() {
eprint!(
"{}",
linked
.diagnostics()
.render_colored(linked.source_map(), args.color)
);
std::process::exit(1);
}
let bytecode = linked.emit().expect("bytecode emission failed");
let module = Module::load(&bytecode).expect("module loading failed");

// Emit TypeScript types
Expand Down
34 changes: 34 additions & 0 deletions crates/plotnik-cli/src/commands/lang_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,40 @@ pub fn resolve_lang_required(lang_name: &str) -> Result<Lang, String> {
plotnik_langs::from_name(lang_name).ok_or_else(|| format!("unknown language: '{}'", lang_name))
}

/// Resolve language with user-friendly error handling.
/// Tries explicit flag first, then infers from query path.
/// Exits with error message if language cannot be determined.
pub fn require_lang(
explicit: Option<&str>,
query_path: Option<&std::path::Path>,
command: &str,
) -> Lang {
if let Some(lang_name) = explicit {
match resolve_lang_required(lang_name) {
Ok(l) => return l,
Err(msg) => {
eprintln!("error: {}", msg);
if let Some(suggestion) = suggest_language(lang_name) {
eprintln!();
eprintln!("Did you mean '{}'?", suggestion);
}
eprintln!();
eprintln!("Run 'plotnik langs' for the full list.");
std::process::exit(1);
}
}
}

if let Some(l) = resolve_lang(None, query_path) {
return l;
}

eprintln!("error: language is required for {}", command);
eprintln!();
eprintln!("hint: use -l <language> to specify the target language");
std::process::exit(1);
}

/// Suggest similar language names for typos.
pub fn suggest_language(input: &str) -> Option<String> {
let input_lower = input.to_lowercase();
Expand Down
4 changes: 2 additions & 2 deletions crates/plotnik-cli/src/commands/run_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use arborium_tree_sitter as tree_sitter;
use plotnik_langs::Lang;
use plotnik_lib::QueryBuilder;
use plotnik_lib::bytecode::{Entrypoint, Module};
use plotnik_lib::emit::emit_linked;
use plotnik_lib::emit::emit;

use super::lang_resolver::{resolve_lang_required, suggest_language};
use super::query_loader::load_query_source;
Expand Down Expand Up @@ -193,7 +193,7 @@ pub fn prepare_query(input: QueryInput) -> PreparedQuery {
std::process::exit(1);
}

let bytecode = emit_linked(&query).expect("emit failed");
let bytecode = emit(&query).expect("emit failed");
let module = Module::load(&bytecode).expect("module load failed");

let entrypoint = resolve_entrypoint(&module, input.entry);
Expand Down
Loading