git.delta.rocks / jrsonnet / refs/commits / 393dcbd419fd

difftreelog

feat(macro) pass call location to builtins

Yaroslav Bolyukin2021-12-26parent: #a5471f2.patch.diff
in: master

8 files changed

addedcmds/jrsonnet-fmt/Cargo.tomldiffbeforeafterboth

no changes

addedcmds/jrsonnet-fmt/src/main.rsdiffbeforeafterboth

no changes

modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
5 equals,5 equals,
6 error::{Error::*, Result},6 error::{Error::*, Result},
7 operator::evaluate_mod_op,7 operator::evaluate_mod_op,
8 parse_args, primitive_equals, push_frame, throw, with_state, ArrValue, Context, FuncVal,8 primitive_equals, push_frame, throw, with_state, ArrValue, Context, FuncVal,
9 IndexableVal, Val,9 IndexableVal, Val,
10};10};
11use format::{format_arr, format_obj};11use format::{format_arr, format_obj};
12use gcmodule::Cc;12use gcmodule::Cc;
13use jrsonnet_interner::IStr;13use jrsonnet_interner::IStr;
14use jrsonnet_parser::{ArgsDesc, ExprLocation};14use jrsonnet_parser::{ArgsDesc, ExprLocation};
15use jrsonnet_types::ty;
16use serde::Deserialize;15use serde::Deserialize;
17use serde_yaml::DeserializingQuirks;16use serde_yaml::DeserializingQuirks;
18use std::{17use std::{
466 Ok(format!("{:x}", md5::compute(&str.as_bytes())))465 Ok(format!("{:x}", md5::compute(&str.as_bytes())))
467}466}
468467
468#[jrsonnet_macros::builtin]
469fn builtin_trace(context: Context, loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {469fn builtin_trace(#[location] loc: &ExprLocation, str: IStr, rest: Any) -> Result<Any> {
470 parse_args!(context, "trace", args, 2, [470 eprint!("TRACE:");
471 0, str: ty!(string) => Val::Str;
472 1, rest: ty!(any);
473 ], {
474 eprint!("TRACE:");
475 with_state(|s|{471 with_state(|s| {
476 let locs = s.map_source_locations(&loc.0, &[loc.1]);472 let locs = s.map_source_locations(&loc.0, &[loc.1]);
477 eprint!(" {}:{}", loc.0.file_name().unwrap().to_str().unwrap(), locs[0].line);473 eprint!(
474 " {}:{}",
475 loc.0.file_name().unwrap().to_str().unwrap(),
476 locs[0].line
477 );
478 });478 });
479 eprintln!(" {}", str);479 eprintln!(" {}", str);
480 Ok(rest)480 Ok(rest) as Result<Any>
481 })
482}481}
483482
484#[jrsonnet_macros::builtin]483#[jrsonnet_macros::builtin]
modifiedcrates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth
16pub enum Error {16pub enum Error {
17 #[error("intrinsic not found: {0}")]17 #[error("intrinsic not found: {0}")]
18 IntrinsicNotFound(IStr),18 IntrinsicNotFound(IStr),
19 #[error("argument reordering in intrisics not supported yet")]
20 IntrinsicArgumentReorderingIsNotSupportedYet,
2119
22 #[error("operator {0} does not operate on type {1}")]20 #[error("operator {0} does not operate on type {1}")]
23 UnaryOperatorDoesNotOperateOnType(UnaryOpType, ValType),21 UnaryOperatorDoesNotOperateOnType(UnaryOpType, ValType),
modifiedcrates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth
312 Ok(body_ctx.extend(out, None, None, None))312 Ok(body_ctx.extend(out, None, None, None))
313}313}
314
315#[macro_export]
316macro_rules! parse_args {
317 ($ctx: expr, $fn_name: expr, $args: expr, $total_args: expr, [
318 $($id: expr, $name: ident: $ty: expr $(=>$match: path)?);+ $(;)?
319 ], $handler:block) => {{
320 use $crate::{error::Error::*, throw, evaluate, push_description_frame, typed::CheckType};
321
322 let args = $args;
323 if args.unnamed.len() + args.named.len() > $total_args {
324 throw!(TooManyArgsFunctionHas($total_args));
325 }
326 $(
327 if args.unnamed.len() + args.named.len() <= $id {
328 throw!(FunctionParameterNotBoundInCall(stringify!($name).into()));
329 }
330 // Is named
331 let $name = if $id >= $args.unnamed.len() {
332 let named = &args.named[$id - $args.unnamed.len()];
333 if &named.0 != stringify!($name) {
334 throw!(IntrinsicArgumentReorderingIsNotSupportedYet);
335 }
336 &named.1
337 } else {
338 &$args.unnamed[$id]
339 };
340 let $name = push_description_frame(|| format!("evaluating builtin argument {}", stringify!($name)), || {
341 let value = evaluate($ctx.clone(), &$name)?;
342 $ty.check(&value)?;
343 Ok(value)
344 })?;
345 $(
346 let $name = if let $match(v) = $name {
347 v
348 } else {
349 unreachable!();
350 };
351 )?
352 )+
353 ($handler as crate::Result<_>)
354 }};
355}
356314
modifiedcrates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth
1use proc_macro2::Span;1use proc_macro2::Span;
2use quote::quote;2use quote::quote;
3use syn::{parse_macro_input, FnArg, Ident, ItemFn, Pat};3use syn::{parse_macro_input, FnArg, Ident, ItemFn, Pat, PatType};
4
5fn is_location_arg(t: &PatType) -> bool {
6 t.attrs.iter().any(|a| a.path.is_ident("location"))
7}
48
5#[proc_macro_attribute]9#[proc_macro_attribute]
6pub fn builtin(10pub fn builtin(
7 _attr: proc_macro::TokenStream,11 _attr: proc_macro::TokenStream,
8 item: proc_macro::TokenStream,12 item: proc_macro::TokenStream,
9) -> proc_macro::TokenStream {13) -> proc_macro::TokenStream {
10 // syn::ItemFn::parse(input)14 // syn::ItemFn::parse(input)
11 let fun: ItemFn = parse_macro_input!(item);15 let mut fun: ItemFn = parse_macro_input!(item);
1216
17 let result = match fun.sig.output {
18 syn::ReturnType::Default => panic!("builtin should return something"),
19 syn::ReturnType::Type(_, ref ty) => ty.clone(),
20 };
21
22 let params = fun
23 .sig
24 .inputs
25 .iter()
26 .map(|i| match i {
27 FnArg::Receiver(_) => unreachable!(),
28 FnArg::Typed(t) => t,
29 })
30 .filter(|a| !is_location_arg(a))
31 .map(|t| {
32 let ident = match &t.pat as &Pat {
33 Pat::Ident(i) => i.ident.to_string(),
34 _ => panic!("only idents supported yet"),
35 };
36 // TODO: Check if ty == Option<_>
37 let optional = false;
38 quote! {
39 BuiltinParam {
40 name: #ident,
41 has_default: #optional,
42 }
43 }
44 })
45 .collect::<Vec<_>>();
46
47 let args = fun
48 .sig
49 .inputs
50 .iter_mut()
51 .map(|i| match i {
52 FnArg::Receiver(_) => unreachable!(),
53 FnArg::Typed(t) => t,
54 })
55 .map(|t| {
56 let count_before = t.attrs.len();
57 t.attrs.retain(|a| !a.path.is_ident("location"));
58 let count_after = t.attrs.len();
59 let is_location = count_before != count_after;
60 if is_location {
61 quote! {{
62 loc
63 }}
64 } else {
65 let ident = match &t.pat as &Pat {
66 Pat::Ident(i) => i.ident.to_string(),
67 _ => panic!("only idents supported yet"),
68 };
69 let ty = &t.ty;
70 quote! {{
71 let value = parsed.get(#ident).unwrap();
72
73 jrsonnet_evaluator::push_description_frame(
74 || format!("argument <{}> evaluation", #ident),
75 || <#ty>::try_from(value.evaluate()?),
76 )?
77 }}
78 }
79 }).collect::<Vec<_>>();
80
13 let inner_name = Ident::new("inner", Span::call_site());81 let inner_name = Ident::new("inner", Span::call_site());
14 let mut inner_fun = fun.clone();82 let mut inner_fun = fun.clone();
15 inner_fun.sig.ident = inner_name.clone();83 inner_fun.sig.ident = inner_name.clone();
16 let result = match fun.sig.output {
17 syn::ReturnType::Default => panic!("builtin should return something"),
18 syn::ReturnType::Type(_, ty) => ty,
19 };
20
21 let params = fun
22 .sig
23 .inputs
24 .iter()
25 .map(|i| match i {
26 FnArg::Receiver(_) => unreachable!(),
27 FnArg::Typed(t) => t,
28 })
29 .map(|t| {
30 let ident = match &t.pat as &Pat {
31 Pat::Ident(i) => i.ident.to_string(),
32 _ => panic!("only idents supported yet"),
33 };
34 // TODO: Check if ty == Option<_>
35 let optional = false;
36 quote! {
37 BuiltinParam {
38 name: #ident,
39 has_default: #optional,
40 }
41 }
42 });
43
44 let args = fun
45 .sig
46 .inputs
47 .iter()
48 .map(|i| match i {
49 FnArg::Receiver(_) => unreachable!(),
50 FnArg::Typed(t) => t,
51 })
52 .map(|t| {
53 let ident = match &t.pat as &Pat {
54 Pat::Ident(i) => i.ident.to_string(),
55 _ => panic!("only idents supported yet"),
56 };
57 let ty = &t.ty;
58 quote! {{
59 let value = parsed.get(#ident).unwrap();
60
61 jrsonnet_evaluator::push_description_frame(
62 || format!("argument <{}> evaluation", #ident),
63 || <#ty>::try_from(value.evaluate()?),
64 )?
65 }}
66 });
6784
68 let attrs = &fun.attrs;85 let attrs = &fun.attrs;
69 let vis = &fun.vis;86 let vis = &fun.vis;
70 let name = &fun.sig.ident;87 let name = &fun.sig.ident;
71 (quote! {88 (quote! {
72 #(#attrs)*89 #(#attrs)*
73 #vis fn #name(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {90 #vis fn #name(context: Context, loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
74 #inner_fun91 #inner_fun
75 use jrsonnet_evaluator::function::BuiltinParam;92 use jrsonnet_evaluator::function::BuiltinParam;
76 const PARAMS: &'static [BuiltinParam] = &[93 const PARAMS: &'static [BuiltinParam] = &[
modifiedcrates/jrsonnet-types/src/lib.rsdiffbeforeafterboth
191 write!(f, "}}")?;191 write!(f, "}}")?;
192 }192 }
193 ComplexValType::Union(v) => write_union(f, true, v.iter())?,193 ComplexValType::Union(v) => write_union(f, true, v.iter())?,
194 ComplexValType::UnionRef(v) => write_union(f, true, v.iter().map(|v| *v))?,194 ComplexValType::UnionRef(v) => write_union(f, true, v.iter().copied())?,
195 ComplexValType::Sum(v) => write_union(f, false, v.iter())?,195 ComplexValType::Sum(v) => write_union(f, false, v.iter())?,
196 ComplexValType::SumRef(v) => write_union(f, false, v.iter().map(|v| *v))?,196 ComplexValType::SumRef(v) => write_union(f, false, v.iter().copied())?,
197 };197 };
198 Ok(())198 Ok(())
199 }199 }
modifiedflake.nixdiffbeforeafterboth
1{1{
2 description = "Rust jsonnet implementation";2 description = "Dotfiles manager";
3
4 inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";3 inputs = {
4 nixpkgs.url = "github:nixos/nixpkgs";
5 inputs.flake-utils.url = "github:numtide/flake-utils";5 flake-utils.url = "github:numtide/flake-utils";
66 naersk.url = "github:nix-community/naersk";
7 rust-overlay.url = "github:oxalica/rust-overlay";
8 pre-commit-hooks.url = "github:cachix/pre-commit-hooks.nix";
9 };
7 outputs = { self, nixpkgs, flake-utils }:10 outputs = { self, nixpkgs, flake-utils, rust-overlay, pre-commit-hooks, naersk }:
8 flake-utils.lib.eachDefaultSystem (system:11 flake-utils.lib.eachDefaultSystem (system:
9 let12 let
10 pkgs = nixpkgs.legacyPackages.${system};13 pkgs = import nixpkgs
14 {
15 inherit system;
16 overlays = [ rust-overlay.overlay ];
17 };
18 rust = ((pkgs.rustChannelOf { date = "2021-11-11"; channel = "nightly"; }).default.override {
19 extensions = [ "rust-src" ];
20 });
11 jrsonnet = pkgs.rustPlatform.buildRustPackage rec {21 naersk-lib = naersk.lib."${system}".override {
12 pname = "jrsonnet";22 rustc = rust;
13 version = "0.1.0";23 cargo = rust;
14 src = self;
15 cargoSha256 = "sha256-cez8pJ/uwj+PHAPQwpSB4CKaxcP8Uvv8xguOrVXR2xE=";
16 };24 };
17 in { 25 in
26 rec {
27 checks = {
28 pre-commit-check = pre-commit-hooks.lib.${system}.run {
29 src = ./.;
30 hooks = {
31 nixpkgs-fmt.enable = true;
32 };
33 };
34 };
18 defaultPackage = jrsonnet;35 defaultPackage = naersk-lib.buildPackage {
36 pname = "dotman";
37 root = ./.;
38 buildInputs = with pkgs; [
39 pkgs.sqlite
40 ];
41 };
19 devShell = pkgs.mkShell {};42 devShell = pkgs.mkShell {
43 inherit (checks.pre-commit-check) shellHook;
44 nativeBuildInputs = with pkgs;[
45 pkgs.binutils
46 pkgs.pkgconfig
47 pkgs.clang
48 pkgs.x11
49 pkgs.alsaLib
50 pkgs.libudev
51 pkgs.sqlite
52 rust
53 cargo-edit
54 go-jsonnet
55 ];
56 };
20 });57 }
58 );